From f6268535be6087566af7b38833eeaf6c9c82edb7 Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Mon, 19 Apr 2021 12:21:47 -0700 Subject: [PATCH 001/234] Add DataFile abstract class The DataFile abstract class is meant to prototype methods for accessing internal data files. Unlike DataObject's these internal datafiles are never meant to be saved or loaded from NWB sinks or sources. --- .../behavior/data_files/__init__.py | 3 ++ .../behavior/data_files/_data_file_abc.py | 53 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 allensdk/brain_observatory/behavior/data_files/__init__.py create mode 100644 allensdk/brain_observatory/behavior/data_files/_data_file_abc.py diff --git a/allensdk/brain_observatory/behavior/data_files/__init__.py b/allensdk/brain_observatory/behavior/data_files/__init__.py new file mode 100644 index 000000000..67cbc7175 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_files/__init__.py @@ -0,0 +1,3 @@ +from allensdk.brain_observatory.behavior.data_files._data_file_abc import DataFile # noqa E501, F401 +from allensdk.brain_observatory.behavior.data_files.stimulus_file import StimulusFile # noqa E501, F401 +from allensdk.brain_observatory.behavior.data_files.sync_file import SyncFile # noqa E501, F401 diff --git a/allensdk/brain_observatory/behavior/data_files/_data_file_abc.py b/allensdk/brain_observatory/behavior/data_files/_data_file_abc.py new file mode 100644 index 000000000..28ca9677a --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_files/_data_file_abc.py @@ -0,0 +1,53 @@ +import abc +from typing import Any, Union +from pathlib import Path + + +class DataFile(abc.ABC): + """An abstract class that prototypes methods for accessing internal + data files. + + These data files contain information necessary to sucessfully instantiate + one or many `DataObject`(s). + + External users should ignore this class (and subclasses) as as they + will only ever be using `from_nwb()` and `to_nwb()` `DataObject` methods. + """ + + def __init__(self, filepath: Union[str, Path]): # pragma: no cover + self._filepath: str = str(filepath) + self._data = self.load_data(filepath=filepath) + + @property + def data(self) -> Any: # pragma: no cover + return self._data + + @property + def filepath(self) -> str: # pragma: no cover + return self._filepath + + @classmethod + @abc.abstractmethod + def from_json(cls) -> "DataFile": # pragma: no cover + # Example: + # filepath = dict_repr["my_data_file_path"] + # return cls.instantiate(filepath=filepath) + raise NotImplementedError() + + @abc.abstractmethod + def to_json(self) -> dict: # pragma: no cover + raise NotImplementedError() + + @classmethod + @abc.abstractmethod + def from_lims(cls) -> "DataFile": # pragma: no cover + # Example: + # query = """SELECT my_file FROM some_lims_table""" + # filepath = dbconn.fetchone(query, strict=True) + # return cls.instantiate(filepath=filepath) + raise NotImplementedError() + + @staticmethod + @abc.abstractmethod + def load_data(filepath: Union[str, Path]) -> Any: # pragma: no cover + raise NotImplementedError() From c123789780ef7bcd5d446151e3a72451d98c9e9b Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Mon, 19 Apr 2021 14:15:58 -0700 Subject: [PATCH 002/234] Add StimulusFile and SyncFile "DataFile" implementations --- .../behavior/data_files/stimulus_file.py | 50 +++++++++++++++++++ .../behavior/data_files/sync_file.py | 48 ++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 allensdk/brain_observatory/behavior/data_files/stimulus_file.py create mode 100644 allensdk/brain_observatory/behavior/data_files/sync_file.py diff --git a/allensdk/brain_observatory/behavior/data_files/stimulus_file.py b/allensdk/brain_observatory/behavior/data_files/stimulus_file.py new file mode 100644 index 000000000..b350e3508 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_files/stimulus_file.py @@ -0,0 +1,50 @@ +import json +from typing import Dict, Union +from pathlib import Path + +import pandas as pd + +from allensdk.internal.api import PostgresQueryMixin +from allensdk.internal.core.lims_utilities import safe_system_path +from allensdk.brain_observatory.behavior.data_files import DataFile + +class StimulusFile(DataFile): + + def __init__(self, filepath: Union[str, Path]): + super().__init__(filepath=filepath) + + @classmethod + def from_json(cls, dict_repr: dict) -> "StimulusFile": + filepath = dict_repr["behavior_stimulus_file"] + return cls(filepath=filepath) + + def to_json(self) -> Dict[str, str]: + return {"behavior_stimulus_file": str(self.filepath)} + + @classmethod + def from_lims( + cls, db: PostgresQueryMixin, + behavior_session_id: Union[int, str] + ) -> "StimulusFile": + # Query returns the path to the StimulusPickle file for the given + # behavior session + query = f""" + SELECT + wkf.storage_directory || wkf.filename AS stim_file + FROM + well_known_files wkf + WHERE + wkf.attachable_id = {behavior_session_id} + AND wkf.attachable_type = 'BehaviorSession' + AND wkf.well_known_file_type_id IN ( + SELECT id + FROM well_known_file_types + WHERE name = 'StimulusPickle'); + """ + filepath = db.fetchone(query, strict=True) + return cls(filepath=filepath) + + @staticmethod + def load_data(filepath: Union[str, Path]) -> dict: + filepath = safe_system_path(file_name=filepath) + return pd.read_pickle(filepath) diff --git a/allensdk/brain_observatory/behavior/data_files/sync_file.py b/allensdk/brain_observatory/behavior/data_files/sync_file.py new file mode 100644 index 000000000..07768f9b0 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_files/sync_file.py @@ -0,0 +1,48 @@ +import json +from typing import Dict, Union +from pathlib import Path + +from allensdk.internal.api import PostgresQueryMixin +from allensdk.internal.core.lims_utilities import safe_system_path +from allensdk.brain_observatory.behavior.sync import get_sync_data +from allensdk.brain_observatory.behavior.data_files import DataFile + + +class SyncFile(DataFile): + + def __init__(self, filepath: Union[str, Path]): + super().__init__(filepath=filepath) + + @classmethod + def from_json(cls, dict_repr: dict) -> "SyncFile": + filepath = dict_repr["sync_file"] + return cls(filepath=filepath) + + def to_json(self) -> Dict[str, str]: + return {"sync_file": str(self.filepath)} + + @classmethod + def from_lims( + cls, db: PostgresQueryMixin, + ophys_experiment_id: Union[int, str] + ) -> "SyncFile": + # Query returns the path to the sync timing file associated with the + # ophys experiment + query = f""" + SELECT wkf.storage_directory || wkf.filename AS sync_file + FROM ophys_experiments oe + JOIN ophys_sessions os ON oe.ophys_session_id = os.id + JOIN well_known_files wkf ON wkf.attachable_id = os.id + JOIN well_known_file_types wkft + ON wkft.id = wkf.well_known_file_type_id + WHERE wkf.attachable_type = 'OphysSession' + AND wkft.name = 'OphysRigSync' + AND oe.id = {ophys_experiment_id}; + """ + filepath = db.fetchone(query, strict=True) + return cls(filepath=filepath) + + @staticmethod + def load_data(filepath: Union[str, Path]) -> dict: + filepath = safe_system_path(file_name=filepath) + return get_sync_data(sync_path=filepath) From a8293d52cfaad18ff2bf14f6cdba605a55079762 Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Wed, 21 Apr 2021 15:11:39 -0700 Subject: [PATCH 003/234] Add selective caching to DataFile classes This is a combination of the following commits: 1) Implement custom arg selective cache decorator Because of the the way this refactor reorganizes data flow there is a very real potential for extremely bad performance when trying to instantiate DataObject instances with nested/interlinked dependencies. Example: Calculation of the running speed dataframe depends on a StimulusFile in addition to Timestamps. Timestamps itself also depends on the StimulusFile and/or the SyncFile. So just for running speed, the stimulus pkl file would need to be read twice. Once for each instantiation of the StimulusFile. Other DataObjects also depend on data in the Timestamps (licks, rewards, metadata, stimulus_frame_rate, etc...). Rereading the same *.pkl file for each instantiation will likely have big performance impacts. This commit introduces a custom arg selective cache decorator which caches the return of classmethod calls if specific arg inputs remain the same. 2) Remove custom cache decorator and use cachetools implementation This commit removes custom cache decorator in favor of functionality in an external package called cachetools. --- .../behavior/data_files/stimulus_file.py | 14 ++++++++++++++ .../behavior/data_files/sync_file.py | 13 +++++++++++++ requirements.txt | 1 + 3 files changed, 28 insertions(+) diff --git a/allensdk/brain_observatory/behavior/data_files/stimulus_file.py b/allensdk/brain_observatory/behavior/data_files/stimulus_file.py index b350e3508..2a7ae7763 100644 --- a/allensdk/brain_observatory/behavior/data_files/stimulus_file.py +++ b/allensdk/brain_observatory/behavior/data_files/stimulus_file.py @@ -2,18 +2,31 @@ from typing import Dict, Union from pathlib import Path +from cachetools import cached, LRUCache +from cachetools.keys import hashkey + import pandas as pd from allensdk.internal.api import PostgresQueryMixin from allensdk.internal.core.lims_utilities import safe_system_path from allensdk.brain_observatory.behavior.data_files import DataFile + +def from_json_cache_key(cls, dict_repr: dict): + return hashkey(json.dumps(dict_repr)) + + +def from_lims_cache_key(cls, db, behavior_session_id: int): + return hashkey(behavior_session_id) + + class StimulusFile(DataFile): def __init__(self, filepath: Union[str, Path]): super().__init__(filepath=filepath) @classmethod + @cached(cache=LRUCache(maxsize=10), key=from_json_cache_key) def from_json(cls, dict_repr: dict) -> "StimulusFile": filepath = dict_repr["behavior_stimulus_file"] return cls(filepath=filepath) @@ -22,6 +35,7 @@ def to_json(self) -> Dict[str, str]: return {"behavior_stimulus_file": str(self.filepath)} @classmethod + @cached(cache=LRUCache(maxsize=10), key=from_lims_cache_key) def from_lims( cls, db: PostgresQueryMixin, behavior_session_id: Union[int, str] diff --git a/allensdk/brain_observatory/behavior/data_files/sync_file.py b/allensdk/brain_observatory/behavior/data_files/sync_file.py index 07768f9b0..4e2b73d76 100644 --- a/allensdk/brain_observatory/behavior/data_files/sync_file.py +++ b/allensdk/brain_observatory/behavior/data_files/sync_file.py @@ -2,18 +2,30 @@ from typing import Dict, Union from pathlib import Path +from cachetools import cached, LRUCache +from cachetools.keys import hashkey + from allensdk.internal.api import PostgresQueryMixin from allensdk.internal.core.lims_utilities import safe_system_path from allensdk.brain_observatory.behavior.sync import get_sync_data from allensdk.brain_observatory.behavior.data_files import DataFile +def from_json_cache_key(cls, dict_repr: dict): + return hashkey(json.dumps(dict_repr)) + + +def from_lims_cache_key(cls, db, ophys_experiment_id: int): + return hashkey(ophys_experiment_id) + + class SyncFile(DataFile): def __init__(self, filepath: Union[str, Path]): super().__init__(filepath=filepath) @classmethod + @cached(cache=LRUCache(maxsize=10), key=from_json_cache_key) def from_json(cls, dict_repr: dict) -> "SyncFile": filepath = dict_repr["sync_file"] return cls(filepath=filepath) @@ -22,6 +34,7 @@ def to_json(self) -> Dict[str, str]: return {"sync_file": str(self.filepath)} @classmethod + @cached(cache=LRUCache(maxsize=10), key=from_lims_cache_key) def from_lims( cls, db: PostgresQueryMixin, ophys_experiment_id: Union[int, str] diff --git a/requirements.txt b/requirements.txt index bac4e8ebc..a7fa1de21 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,3 +28,4 @@ tqdm>=4.27 ndx-events<=0.2.0 boto3==1.17.21 semver +cachetools>=4.2.1,<5.0.0 \ No newline at end of file From 910a4272fa6f8cb3dd3ed1ad81c61ea807d1880e Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Thu, 22 Apr 2021 09:14:27 -0700 Subject: [PATCH 004/234] Add stubs for other DataFiles --- .../brain_observatory/behavior/data_files/avg_projection_file.py | 0 allensdk/brain_observatory/behavior/data_files/demix_file.py | 0 allensdk/brain_observatory/behavior/data_files/dff_file.py | 0 .../brain_observatory/behavior/data_files/event_detection_file.py | 0 .../brain_observatory/behavior/data_files/eye_tracking_file.py | 0 .../brain_observatory/behavior/data_files/max_projection_file.py | 0 .../behavior/data_files/rigid_motion_transform_file.py | 0 7 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 allensdk/brain_observatory/behavior/data_files/avg_projection_file.py create mode 100644 allensdk/brain_observatory/behavior/data_files/demix_file.py create mode 100644 allensdk/brain_observatory/behavior/data_files/dff_file.py create mode 100644 allensdk/brain_observatory/behavior/data_files/event_detection_file.py create mode 100644 allensdk/brain_observatory/behavior/data_files/eye_tracking_file.py create mode 100644 allensdk/brain_observatory/behavior/data_files/max_projection_file.py create mode 100644 allensdk/brain_observatory/behavior/data_files/rigid_motion_transform_file.py diff --git a/allensdk/brain_observatory/behavior/data_files/avg_projection_file.py b/allensdk/brain_observatory/behavior/data_files/avg_projection_file.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_files/demix_file.py b/allensdk/brain_observatory/behavior/data_files/demix_file.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_files/dff_file.py b/allensdk/brain_observatory/behavior/data_files/dff_file.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_files/event_detection_file.py b/allensdk/brain_observatory/behavior/data_files/event_detection_file.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_files/eye_tracking_file.py b/allensdk/brain_observatory/behavior/data_files/eye_tracking_file.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_files/max_projection_file.py b/allensdk/brain_observatory/behavior/data_files/max_projection_file.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_files/rigid_motion_transform_file.py b/allensdk/brain_observatory/behavior/data_files/rigid_motion_transform_file.py new file mode 100644 index 000000000..e69de29bb From 6bd95954407864dba3e7fe7e836047d084cff202 Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Thu, 22 Apr 2021 11:33:50 -0700 Subject: [PATCH 005/234] Add DataObject abstract class --- .../behavior/data_objects/__init__.py | 1 + .../behavior/data_objects/_data_object_abc.py | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 allensdk/brain_observatory/behavior/data_objects/__init__.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py diff --git a/allensdk/brain_observatory/behavior/data_objects/__init__.py b/allensdk/brain_observatory/behavior/data_objects/__init__.py new file mode 100644 index 000000000..89f110b42 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/__init__.py @@ -0,0 +1 @@ +from allensdk.brain_observatory.behavior.data_objects._data_object_abc import DataObject # noqa: E501, F401 diff --git a/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py new file mode 100644 index 000000000..4a61a2834 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py @@ -0,0 +1,50 @@ +import abc +from typing import Any + +from pynwb import NWBFile + + +class DataObject(abc.ABC): + """An abstract class that prototypes properties that represent a + category of experimental data/metadata (e.g. running speed, + rewards, licks, etc.) and that prototypes methods to allow conversion of + the experimental data/metadata to and from various + data sources and sinks (e.g. LIMS, JSON, NWB). + """ + + def __init__(self, name: str, value: Any): + self._name = name + self._value = value + + @property + def name(self) -> str: + return self._name + + @property + def value(self) -> Any: + return self._value + + @classmethod + @abc.abstractmethod + def from_json(cls) -> "DataObject": # pragma: no cover + raise NotImplementedError() + + @classmethod + @abc.abstractmethod + def from_lims(cls) -> "DataObject": # pragma: no cover + # Example: + # return cls(name="my_data_object", value=42) + raise NotImplementedError() + + @classmethod + @abc.abstractmethod + def from_nwb(cls, nwbfile: NWBFile) -> "DataObject": # pragma: no cover + raise NotImplementedError() + + @abc.abstractmethod + def to_json(self) -> dict: # pragma: no cover + raise NotImplementedError() + + @abc.abstractmethod + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: # pragma: no cover + raise NotImplementedError() From 1870a7106e83dd12eb4bd6d3dd781ce64bc46eed Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Thu, 22 Apr 2021 13:53:24 -0700 Subject: [PATCH 006/234] Add StimulusTimestamps DataObject and associated processing --- .../behavior/data_objects/__init__.py | 1 + .../stimulus_timestamps/__init__.py | 0 .../stimulus_timestamps.py | 126 ++++++++++++++++++ .../timestamps_processing.py | 49 +++++++ 4 files changed, 176 insertions(+) create mode 100644 allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/__init__.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/timestamps_processing.py diff --git a/allensdk/brain_observatory/behavior/data_objects/__init__.py b/allensdk/brain_observatory/behavior/data_objects/__init__.py index 89f110b42..e8670965d 100644 --- a/allensdk/brain_observatory/behavior/data_objects/__init__.py +++ b/allensdk/brain_observatory/behavior/data_objects/__init__.py @@ -1 +1,2 @@ from allensdk.brain_observatory.behavior.data_objects._data_object_abc import DataObject # noqa: E501, F401 +from allensdk.brain_observatory.behavior.data_objects.stimulus_timestamps.stimulus_timestamps import StimulusTimestamps # noqa: E501, F401 diff --git a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/__init__.py b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py new file mode 100644 index 000000000..7aac1fbb4 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py @@ -0,0 +1,126 @@ + +import json +from typing import Optional + +from cachetools import cached, LRUCache +from cachetools.keys import hashkey + +import numpy as np +from pynwb import NWBFile, ProcessingModule +from pynwb.base import TimeSeries + +from allensdk.internal.api import PostgresQueryMixin +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_files import ( + StimulusFile, SyncFile +) +from allensdk.brain_observatory.behavior.data_objects.stimulus_timestamps.timestamps_processing import ( # noqa: E501 + get_behavior_stimulus_timestamps, get_ophys_stimulus_timestamps +) + + +def from_json_cache_key(cls, dict_repr: dict): + return hashkey(json.dumps(dict_repr)) + + +def from_lims_cache_key( + cls, db, behavior_session_id: int, ophys_experiment_id: int +): + return hashkey(behavior_session_id, ophys_experiment_id) + + +class StimulusTimestamps(DataObject): + + def __init__( + self, + timestamps: np.ndarray, + stimulus_file: Optional[StimulusFile] = None, + sync_file: Optional[SyncFile] = None + ): + super().__init__(name="stimulus_timestamps", value=timestamps) + self._stimulus_file = stimulus_file + self._sync_file = sync_file + + @classmethod + @cached(cache=LRUCache(maxsize=10), key=from_json_cache_key) + def from_json(cls, dict_repr: dict) -> "StimulusTimestamps": + stimulus_file = StimulusFile.from_json(dict_repr) + + if "sync_file" in dict_repr: + sync_file = SyncFile.from_json(dict_repr) + stimulus_timestamps = get_ophys_stimulus_timestamps( + sync_path=sync_file.filepath + ) + else: + sync_file = None + stimulus_timestamps = get_behavior_stimulus_timestamps( + stimulus_pkl=stimulus_file.data + ) + + return cls( + timestamps=stimulus_timestamps, + stimulus_file=stimulus_file, + sync_file=sync_file + ) + + def to_json(self) -> dict: + if self._stimulus_file is None: + raise RuntimeError( + "StimulusTimestamps DataObject lacks information about the " + "StimulusFile. This is likely due to instantiating from NWB " + "which prevents to_json() functionality" + ) + + output_dict = dict() + output_dict.update(self._stimulus_file.to_json()) + if self._sync_file is not None: + output_dict.update(self._sync_file.to_json()) + return output_dict + + @classmethod + @cached(cache=LRUCache(maxsize=10), key=from_lims_cache_key) + def from_lims( + cls, + db: PostgresQueryMixin, + behavior_session_id: int, + ophys_experiment_id: Optional[int] = None + ) -> "StimulusTimestamps": + stimulus_file = StimulusFile.from_lims(db, behavior_session_id) + + if ophys_experiment_id: + sync_file = SyncFile.from_lims(db, ophys_experiment_id) + stimulus_timestamps = get_ophys_stimulus_timestamps( + sync_path=sync_file.filepath + ) + else: + sync_file = None + stimulus_timestamps = get_behavior_stimulus_timestamps( + stimulus_pkl=stimulus_file.data + ) + + return cls( + timestamps=stimulus_timestamps, + stimulus_file=stimulus_file, + sync_file=sync_file + ) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "StimulusTimestamps": + stim_module = nwbfile.processing["stimulus"] + stim_ts_interface = stim_module.get_data_interface("timestamps") + stim_timestamps = stim_ts_interface.timestamps[:] + return cls(timestamps=stim_timestamps) + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + stimulus_ts = TimeSeries( + data=self._value, + name="timestamps", + timestamps=self._value, + unit="s" + ) + + stim_mod = ProcessingModule("stimulus", "Stimulus Times processing") + stim_mod.add_data_interface(stimulus_ts) + nwbfile.add_processing_module(stim_mod) + + return nwbfile diff --git a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/timestamps_processing.py b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/timestamps_processing.py new file mode 100644 index 000000000..b34f9b0e1 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/timestamps_processing.py @@ -0,0 +1,49 @@ +from typing import Union +from pathlib import Path + +import numpy as np + +from allensdk.internal.brain_observatory.time_sync import OphysTimeAligner + + +def get_behavior_stimulus_timestamps(stimulus_pkl: dict) -> np.ndarray: + """Obtain visual behavior stimuli timing information from a behavior + stimulus *.pkl file. + + Parameters + ---------- + stimulus_pkl : dict + A dictionary containing stimulus presentation timing information + during a behavior session. Presentation timing info is stored as + an array of times between frames (frame time intervals) in + milliseconds. + + Returns + ------- + np.ndarray + Timestamps (in seconds) for presented stimulus frames during a session. + """ + vsyncs = stimulus_pkl["items"]["behavior"]["intervalsms"] + stimulus_timestamps = np.hstack((0, vsyncs)).cumsum() / 1000.0 + return stimulus_timestamps + + +def get_ophys_stimulus_timestamps(sync_path: Union[str, Path]) -> np.ndarray: + """Obtain visual behavior stimuli timing information from a sync *.h5 file. + + Parameters + ---------- + sync_path : Union[str, Path] + The path to a sync *.h5 file that contains global timing information + about multiple data streams (e.g. behavior, ophys, eye_tracking) + during a session. + + Returns + ------- + np.ndarray + Timestamps (in seconds) for presented stimulus frames during a + behavior + ophys session. + """ + aligner = OphysTimeAligner(sync_file=sync_path) + stimulus_timestamps, _ = aligner.clipped_stim_timestamps + return stimulus_timestamps From 36e784d007aed079e3cad2b255ca83cdbbeb1330 Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Thu, 22 Apr 2021 17:26:16 -0700 Subject: [PATCH 007/234] Add running speed related DataObjects and processing This is a combination of the following commits: 1) Move running_processing functionality Moves running_processing.py from: allensdk/brain_observatory/behavior/running_processing.py To: allensdk/brain_observatory/behavior/data_objects/running_speed/running_processing.py 2) Add RunningSpeed DataObject class 3) Add RunningAcquisition DataObject class --- .../behavior/data_objects/__init__.py | 2 + .../data_objects/running_speed/__init__.py | 0 .../running_speed/running_acquisition.py | 171 +++++++++++ .../running_speed}/running_processing.py | 9 +- .../running_speed/running_speed.py | 179 +++++++++++ .../behavior/test_running_processing.py | 285 ------------------ 6 files changed, 358 insertions(+), 288 deletions(-) create mode 100644 allensdk/brain_observatory/behavior/data_objects/running_speed/__init__.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py rename allensdk/brain_observatory/behavior/{ => data_objects/running_speed}/running_processing.py (98%) create mode 100644 allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py delete mode 100644 allensdk/test/brain_observatory/behavior/test_running_processing.py diff --git a/allensdk/brain_observatory/behavior/data_objects/__init__.py b/allensdk/brain_observatory/behavior/data_objects/__init__.py index e8670965d..1d1eaf7fe 100644 --- a/allensdk/brain_observatory/behavior/data_objects/__init__.py +++ b/allensdk/brain_observatory/behavior/data_objects/__init__.py @@ -1,2 +1,4 @@ from allensdk.brain_observatory.behavior.data_objects._data_object_abc import DataObject # noqa: E501, F401 from allensdk.brain_observatory.behavior.data_objects.stimulus_timestamps.stimulus_timestamps import StimulusTimestamps # noqa: E501, F401 +from allensdk.brain_observatory.behavior.data_objects.running_speed.running_speed import RunningSpeed # noqa: E501, F401 +from allensdk.brain_observatory.behavior.data_objects.running_speed.running_acquisition import RunningAcquisition # noqa: E501, F401 diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/__init__.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py new file mode 100644 index 000000000..acd8e9a61 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py @@ -0,0 +1,171 @@ + +import json +from typing import Optional + +from cachetools import cached, LRUCache +from cachetools.keys import hashkey + +import pandas as pd + +from pynwb import NWBFile, ProcessingModule +from pynwb.base import TimeSeries + +from allensdk.internal.api import PostgresQueryMixin +from allensdk.brain_observatory.behavior.data_objects import ( + DataObject, StimulusTimestamps +) +from allensdk.brain_observatory.behavior.data_files import ( + StimulusFile +) +from allensdk.brain_observatory.behavior.data_objects.running_speed.running_processing import ( # noqa: E501 + get_running_df +) + + +def from_json_cache_key( + cls, dict_repr: dict +): + return hashkey(json.dumps(dict_repr)) + + +def from_lims_cache_key( + cls, db, behavior_session_id: int, ophys_experiment_id: Optional[int] +): + return hashkey( + behavior_session_id, ophys_experiment_id + ) + + +class RunningAcquisition(DataObject): + def __init__( + self, + running_acquisition: pd.DataFrame, + stimulus_file: Optional[StimulusFile] = None, + stimulus_timestamps: Optional[StimulusTimestamps] = None, + ): + super().__init__(name='running_acquisition', value=running_acquisition) + self._stimulus_file = stimulus_file + self._stimulus_timestamps = stimulus_timestamps + + @classmethod + @cached(cache=LRUCache(maxsize=10), key=from_json_cache_key) + def from_json( + cls, + dict_repr: dict, + ) -> "RunningAcquisition": + stimulus_file = StimulusFile.from_json(dict_repr) + stimulus_timestamps = StimulusTimestamps.from_json(dict_repr) + running_acq_df = get_running_df( + data=stimulus_file.data, time=stimulus_timestamps.value, + ) + running_acq_df.drop("speed", axis=1, inplace=True) + + return cls( + running_acquisition=running_acq_df, + stimulus_file=stimulus_file, + stimulus_timestamps=stimulus_timestamps, + ) + + def to_json(self) -> dict: + if self._stimulus_file is None or self._stimulus_timestamps is None: + raise RuntimeError( + "RunningAcquisition DataObject lacks information about the " + "StimulusFile or StimulusTimestamps. This is likely due to " + "instantiating from NWB which prevents to_json() functionality" + ) + output_dict = dict() + output_dict.update(self._stimulus_file.to_json()) + output_dict.update(self._stimulus_timestamps.to_json()) + return output_dict + + @classmethod + @cached(cache=LRUCache(maxsize=10), key=from_lims_cache_key) + def from_lims( + cls, + db: PostgresQueryMixin, + behavior_session_id: int, + ophys_experiment_id: Optional[int] = None, + ) -> "RunningAcquisition": + stimulus_file = StimulusFile.from_lims(db, behavior_session_id) + stimulus_timestamps = StimulusTimestamps.from_lims( + db, behavior_session_id, ophys_experiment_id + ) + running_acq_df = get_running_df( + data=stimulus_file.data, time=stimulus_timestamps.value, + ) + running_acq_df.drop("speed", axis=1, inplace=True) + + return cls( + running_acquisition=running_acq_df, + stimulus_file=stimulus_file, + stimulus_timestamps=stimulus_timestamps, + ) + + @classmethod + def from_nwb( + cls, + nwbfile: NWBFile + ) -> "RunningAcquisition": + running_module = nwbfile.modules['running'] + dx_interface = running_module.get_data_interface('dx') + + dx = dx_interface.data + v_in = nwbfile.get_acquisition('v_in').data + v_sig = nwbfile.get_acquisition('v_sig').data + timestamps = dx_interface.timestamps[:] + + running_acq_df = pd.DataFrame( + { + 'dx': dx, + 'v_in': v_in, + 'v_sig': v_sig + }, + index=pd.Index(timestamps, name='timestamps') + ) + return cls(running_acquisition=running_acq_df) + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + running_acquisition_df: pd.DataFrame = self.value + + running_dx_series = TimeSeries( + name='dx', + data=running_acquisition_df['dx'].values, + timestamps=running_acquisition_df.index.values, + unit='cm', + description=( + 'Running wheel angular change, computed during data collection' + ) + ) + v_sig = TimeSeries( + name='v_sig', + data=running_acquisition_df['v_sig'].values, + timestamps=running_acquisition_df.index.values, + unit='V', + description='Voltage signal from the running wheel encoder' + ) + v_in = TimeSeries( + name='v_in', + data=running_acquisition_df['v_in'].values, + timestamps=running_acquisition_df.index.values, + unit='V', + description=( + 'The theoretical maximum voltage that the running wheel ' + 'encoder will reach prior to "wrapping". This should ' + 'theoretically be 5V (after crossing 5V goes to 0V, or ' + 'vice versa). In practice the encoder does not always ' + 'reach this value before wrapping, which can cause ' + 'transient spikes in speed at the voltage "wraps".') + ) + + if 'running' in nwbfile.processing: + running_mod = nwbfile.processing['running'] + else: + running_mod = ProcessingModule('running', + 'Running speed processing module') + nwbfile.add_processing_module(running_mod) + + running_mod.add_data_interface(running_dx_series) + nwbfile.add_acquisition(v_sig) + nwbfile.add_acquisition(v_in) + + return nwbfile diff --git a/allensdk/brain_observatory/behavior/running_processing.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_processing.py similarity index 98% rename from allensdk/brain_observatory/behavior/running_processing.py rename to allensdk/brain_observatory/behavior/data_objects/running_speed/running_processing.py index 186c8b2ab..7222cb7d1 100644 --- a/allensdk/brain_observatory/behavior/running_processing.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_processing.py @@ -3,7 +3,7 @@ import numpy as np import pandas as pd import warnings -from typing import Iterable, Union, Any, Optional +from typing import Iterable, Union, Optional def calc_deriv(x, time): @@ -299,7 +299,9 @@ def _zscore_threshold_1d(data: np.ndarray, return corrected_data -def get_running_df(data, time: np.ndarray, lowpass: bool = True, zscore_threshold=10.0): +def get_running_df( + data, time: np.ndarray, lowpass: bool = True, zscore_threshold=10.0 +): """ Given the data from the behavior 'pkl' file object and a 1d array of timestamps, compute the running speed. Returns a @@ -318,7 +320,8 @@ def get_running_df(data, time: np.ndarray, lowpass: bool = True, zscore_threshol Whether to apply a 10Hz low-pass filter to the running speed data. zscore_threshold: float - The threshold to use for removing outlier running speeds which might be noise and not true signal + The threshold to use for removing outlier running speeds which might + be noise and not true signal. Returns ------- diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py new file mode 100644 index 000000000..7b492b9d2 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py @@ -0,0 +1,179 @@ + +import json +from typing import Optional + +from cachetools import cached, LRUCache +from cachetools.keys import hashkey + +import pandas as pd + +from pynwb import NWBFile, ProcessingModule +from pynwb.base import TimeSeries + +from allensdk.core.exceptions import DataFrameIndexError +from allensdk.internal.api import PostgresQueryMixin +from allensdk.brain_observatory.behavior.data_objects import ( + DataObject, StimulusTimestamps +) +from allensdk.brain_observatory.behavior.data_files import ( + StimulusFile +) +from allensdk.brain_observatory.behavior.data_objects.running_speed.running_processing import ( # noqa: E501 + get_running_df +) + + +def from_json_cache_key( + cls, dict_repr: dict, filtered: bool, zscore_threshold: float +): + return hashkey(json.dumps(dict_repr), filtered, zscore_threshold) + + +def from_lims_cache_key( + cls, db, behavior_session_id: int, ophys_experiment_id: Optional[int], + filtered: bool, zscore_threshold: float +): + return hashkey( + behavior_session_id, ophys_experiment_id, filtered, zscore_threshold + ) + + +class RunningSpeed(DataObject): + def __init__( + self, + running_speed: pd.DataFrame, + stimulus_file: Optional[StimulusFile] = None, + stimulus_timestamps: Optional[StimulusTimestamps] = None, + filtered: bool = True + ): + super().__init__(name='running_speed', value=running_speed) + self._stimulus_file = stimulus_file + self._stimulus_timestamps = stimulus_timestamps + self._filtered = filtered + + @staticmethod + def _get_running_speed_df( + stimulus_file: StimulusFile, + stimulus_timestamps: StimulusTimestamps, + filtered: bool = True, + zscore_threshold: float = 1.0 + ) -> pd.DataFrame: + running_data_df = get_running_df( + data=stimulus_file.data, time=stimulus_timestamps.value, + lowpass=filtered, zscore_threshold=zscore_threshold + ) + if running_data_df.index.name != "timestamps": + raise DataFrameIndexError( + f"Expected running_data_df index to be named 'timestamps' " + f"But instead got: '{running_data_df.index.name}'" + ) + running_speed = pd.DataFrame({ + "timestamps": running_data_df.index.values, + "speed": running_data_df.speed.values + }) + return running_speed + + @classmethod + @cached(cache=LRUCache(maxsize=10), key=from_json_cache_key) + def from_json( + cls, + dict_repr: dict, + filtered: bool = True, + zscore_threshold: float = 10.0 + ) -> "RunningSpeed": + stimulus_file = StimulusFile.from_json(dict_repr) + stimulus_timestamps = StimulusTimestamps.from_json(dict_repr) + + running_speed = cls._get_running_speed_df( + stimulus_file, stimulus_timestamps, filtered, zscore_threshold + ) + return cls( + running_speed=running_speed, + stimulus_file=stimulus_file, + stimulus_timestamps=stimulus_timestamps, + filtered=filtered) + + def to_json(self) -> dict: + if self._stimulus_file is None or self._stimulus_timestamps is None: + raise RuntimeError( + "RunningSpeed DataObject lacks information about the " + "StimulusFile or StimulusTimestamps. This is likely due to " + "instantiating from NWB which prevents to_json() functionality" + ) + output_dict = dict() + output_dict.update(self._stimulus_file.to_json()) + output_dict.update(self._stimulus_timestamps.to_json()) + return output_dict + + @classmethod + @cached(cache=LRUCache(maxsize=10), key=from_lims_cache_key) + def from_lims( + cls, + db: PostgresQueryMixin, + behavior_session_id: int, + ophys_experiment_id: Optional[int] = None, + filtered: bool = True, + zscore_threshold: float = 10.0 + ) -> "RunningSpeed": + stimulus_file = StimulusFile.from_lims(db, behavior_session_id) + stimulus_timestamps = StimulusTimestamps.from_lims( + db, behavior_session_id, ophys_experiment_id + ) + + running_speed = cls._get_running_speed_df( + stimulus_file, stimulus_timestamps, filtered, zscore_threshold + ) + return cls( + running_speed=running_speed, + stimulus_file=stimulus_file, + stimulus_timestamps=stimulus_timestamps, + filtered=filtered + ) + + @classmethod + def from_nwb( + cls, + nwbfile: NWBFile, + filtered=True + ) -> "RunningSpeed": + running_module = nwbfile.modules['running'] + interface_name = 'speed' if filtered else 'speed_unfiltered' + running_interface = running_module.get_data_interface(interface_name) + + timestamps = running_interface.timestamps[:] + values = running_interface.data[:] + + running_speed = pd.DataFrame( + { + "timestamps": timestamps, + "speed": values + } + ) + return cls(running_speed=running_speed, filtered=filtered) + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + running_speed: pd.DataFrame = self.value + data = running_speed['speed'].values + timestamps = running_speed['timestamps'].values + + if self._filtered: + data_interface_name = "speed" + else: + data_interface_name = "speed_unfiltered" + + running_speed_series = TimeSeries( + name=data_interface_name, + data=data, + timestamps=timestamps, + unit='cm/s') + + if 'running' in nwbfile.processing: + running_mod = nwbfile.processing['running'] + else: + running_mod = ProcessingModule('running', + 'Running speed processing module') + nwbfile.add_processing_module(running_mod) + + running_mod.add_data_interface(running_speed_series) + + return nwbfile diff --git a/allensdk/test/brain_observatory/behavior/test_running_processing.py b/allensdk/test/brain_observatory/behavior/test_running_processing.py deleted file mode 100644 index 3b2e3712f..000000000 --- a/allensdk/test/brain_observatory/behavior/test_running_processing.py +++ /dev/null @@ -1,285 +0,0 @@ -import numpy as np -import pandas as pd -import pytest - -from allensdk.brain_observatory.behavior.running_processing import ( - get_running_df, calc_deriv, deg_to_dist, _shift, _identify_wraps, - _unwrap_voltage_signal, _angular_change, _zscore_threshold_1d, - _clip_speed_wraps) - -import allensdk.brain_observatory.behavior.running_processing as rp - - -@pytest.fixture -def timestamps(): - return np.arange(0., 10., 0.1) - - -@pytest.fixture -def running_data(): - rng = np.random.default_rng() - return { - "items": { - "behavior": { - "encoders": [ - { - "dx": rng.random((100,)), - "vsig": rng.uniform(low=0.0, high=5.1, size=(100,)), - "vin": rng.uniform(low=4.9, high=5.0, size=(100,)), - }]}}} - - -@pytest.mark.parametrize( - "x,time,expected", [ - ([1.0, 1.0], [1.0, 2.0], [np.nan, 0.0]), - ([1.0, 2.0, 3.0], [1.0, 2.0, 3.0], [np.nan, 1.0, 1.0]), - ([1.0, 2.0, 3.0], [1.0, 4.0, 6.0], [np.nan, 1.0/3.0, 1.0/2.0]) - ] -) -def test_calc_deriv(x, time, expected): - obtained = calc_deriv(x, time) - - # np.nan == np.nan returns False so filter out the first values - obtained = obtained[1:] - expected = expected[1:] - - assert np.all(obtained == expected) - - -@pytest.mark.parametrize( - "speed,expected", [ - (np.array([1.0]), [5.5033]), - (np.array([0., 2.0]), [0., 11.0066]) - ] -) -def test_deg_to_dist(speed, expected): - np.testing.assert_allclose(deg_to_dist(speed), expected, atol=0.0001) - - -@pytest.mark.parametrize( - "lowpass", [True, False] -) -def test_get_running_df(running_data, timestamps, lowpass): - actual = get_running_df(running_data, timestamps, lowpass=lowpass) - np.testing.assert_array_equal(actual.index, timestamps) - assert sorted(list(actual)) == ["dx", "speed", "v_in", "v_sig"] - # Should bring raw data through - np.testing.assert_array_equal( - actual["v_sig"].values, - running_data["items"]["behavior"]["encoders"][0]["vsig"]) - np.testing.assert_array_equal( - actual["v_in"].values, - running_data["items"]["behavior"]["encoders"][0]["vin"]) - np.testing.assert_array_equal( - actual["dx"].values, - running_data["items"]["behavior"]["encoders"][0]["dx"]) - if lowpass: - assert np.count_nonzero(np.isnan(actual["speed"])) == 0 - - -@pytest.mark.parametrize( - "lowpass", [True, False] -) -def test_get_running_df_one_fewer_timestamp_check_warning(running_data, - timestamps, - lowpass): - with pytest.warns( - UserWarning, - match="Time array is 1 value shorter than encoder array.*" - ): - # Call with one fewer timestamp, check for a warning - _ = get_running_df( - data=running_data, - time=timestamps[:-1], - lowpass=lowpass - ) - - -@pytest.mark.parametrize( - "lowpass", [True, False] -) -def test_get_running_df_one_fewer_timestamp_check_truncation(running_data, - timestamps, - lowpass): - # Call with one fewer timestamp - output = get_running_df( - data=running_data, - time=timestamps[:-1], - lowpass=lowpass - ) - - # Check that the output is actually trimmed, and the values are the same - assert len(output) == len(timestamps) - 1 - np.testing.assert_equal(output["v_sig"], running_data["items"]["behavior"]["encoders"][0]["vsig"][:-1]) - np.testing.assert_equal(output["v_in"], running_data["items"]["behavior"]["encoders"][0]["vin"][:-1]) - - -@pytest.mark.parametrize( - "arr, periods, fill, expected", - [ - ([1, 2, 3], 1, None, np.array([np.nan, 1., 2.])), - ([1, 2, 3], 2, 99., np.array([99., 99., 1.])), - ([1, 2, 3], 3, 99., np.array([99., 99., 99.])), - ([1, 2, 3], 4, 99., np.array([99., 99., 99.])), - ([], 2, 30, np.array([])) - ] -) -def test_shift(arr, periods, fill, expected): - actual = _shift(arr, periods, fill) - np.testing.assert_array_equal(actual, expected) - - -@pytest.mark.parametrize( - "periods", [0, -2] -) -def test_shift_raises_error_periods_zero(periods): - with pytest.raises(ValueError, match="Can only shift"): - _shift(np.ones((5,)), periods) - - -@pytest.mark.parametrize( - "arr, min_threshold, max_threshold, expected", - [ - (np.array( - [0, 2, 5, 0, # pos wrap 5-0 - 2, 0, 5 # neg wrap 0-5 - ]), 1.5, 3.5, (np.array([3]), np.array([6]))), - (np.array([0, 2, 5, 0, 2, 5]), 0, 5, (np.array([]), np.array([]))), - ] -) -def test_identify_wraps(arr, min_threshold, max_threshold, expected): - actual = _identify_wraps( - arr, min_threshold=min_threshold, max_threshold=max_threshold) - np.testing.assert_array_equal( - actual[0], expected[0], - f"error identifying positive wraps, got {actual[0]}, " - f"expected {expected[0]}") - np.testing.assert_array_equal( - actual[1], expected[1], - f"error identifying negative wraps, got {actual[1]}, " - f"expected {expected[1]}") - - -@pytest.mark.parametrize( - "vsig, pos_wrap_ix, neg_wrap_ix, vmax, max_threshold, max_diff, expected", - [ - ( # No artifacts or baseline - np.array([0, 1, 3, 5, 0.5, 1, 2.5, 5, 0, 1, 4, 3]), - np.array([4, 8]), np.array([10]), 5.0, 5.1, 3.0, - np.array([np.nan, 1, 3, 5, 5.5, 6, 7.5, 10, 10, 11, 9, 8]) - ), - ( # Some diff artifacts, baseline - np.array([1, 1, 3, 5, 0.5, 1, 2.5, 5, 0, 1, 4, 1.5]), - np.array([4, 8]), np.array([10]), 5.0, 5.1, 2.0, - np.array([np.nan, 1, 3, 5, 5.5, 6, 7.5, np.nan, 7.5, 8.5, 6.5, - np.nan]) - ), - ( # Max artifact -- use threshold instead - np.array([0, 7, 3, 5, 0.5, 1]), - np.array([2, 4]), np.array([]).astype(int), None, 5.1, 6.0, - np.array([np.nan, np.nan, 1, 3, 3.5, 4]) - ), - ( - # No wraps - np.ones(5,), np.array([]), np.array([]), 5.0, 5.1, 3.0, - np.array([np.nan, 1., 1., 1., 1.]) - ) - ] -) -def test_unwrap_voltage_signal( - vsig, pos_wrap_ix, neg_wrap_ix, vmax, max_threshold, max_diff, - expected): - actual = _unwrap_voltage_signal( - vsig, pos_wrap_ix, neg_wrap_ix, vmax=vmax, - max_threshold=max_threshold, max_diff=max_diff) - np.testing.assert_array_equal(actual, expected) - - -@pytest.mark.parametrize( - "vsig, vmax, expected", - [ - ( - np.array([1, 2, 3, 4, 5]), 2.0, - np.array([np.nan, np.pi, np.pi, np.pi, np.pi]) - ), - ( - np.array([np.nan, 1, 3, np.nan, 4]), - np.array([2.0, 2.0, 2.0, 2.0, 2.0]), - np.array([np.nan, np.nan, 2*np.pi, np.nan, np.nan]), - ) - ] -) -def test_angular_change(vsig, vmax, expected): - actual = _angular_change(vsig, vmax) - np.testing.assert_allclose(actual, expected, equal_nan=True) - - -@pytest.mark.parametrize( - "arr, threshold, expected", - [ - (np.ones(5,), 2.0, np.ones(5,)), - (np.array([99, 1, np.nan, 1, 1, 1]), 1.5, - np.array([np.nan, 1, np.nan, 1, 1, 1])), - (np.ones(1,), 2.0, np.ones(1,)) - ] -) -def test_zscore_threshold_1d(arr, threshold, expected): - actual = _zscore_threshold_1d(arr, threshold=threshold) - np.testing.assert_allclose(actual, expected, equal_nan=True) - - -@pytest.mark.parametrize( - "speed, time, wrap_indices, span, expected", - [ - ( # Clip bottom, then clip top, then no clip required - np.array([0, 0, -1, 5, 0, 99, 6, 1, 2, 3]), - np.array(range(10)).astype(float), - [2, 5, 8], - 1.0, - np.array([0, 0, 0, 5, 0, 6, 6, 1, 2, 3]) - ), - ] -) -def test_clip_speed_wraps( - speed, time, wrap_indices, span, expected, monkeypatch): - monkeypatch.setattr(rp, "_local_boundaries", lambda x, y, z: (y-1, y+1)) - actual = _clip_speed_wraps(speed, time, wrap_indices, span) - np.testing.assert_array_equal(actual, expected) - - -@pytest.mark.parametrize( - "time, index, span", - [ - (np.arange(10.), 0, 2.0), # no neighborhood before first point - (np.arange(10.), 9, 2.0), # no neighborhood after last point - (np.arange(10.), 4, 0.25), # data not sampled with enough frequency - ] -) -def test_local_boundaries_raises_warning(time, index, span): - with pytest.warns(UserWarning, match="Unable to find"): - rp._local_boundaries(time, index, span) - - -@pytest.mark.parametrize( - "time, index", - [ - (np.array([5., 4., 3., 4., 5.]), 2), - (np.array([1., 2., 3., 2., 1.]), 2), - (np.array([3., 3., 3., 2., 1.]), 2), - ] -) -def test_local_boundaries_raises_error_non_monotonic(time, index): - with pytest.raises(ValueError, match="Data do not monotonically"): - rp._local_boundaries(time, index, 1.0) - - -@pytest.mark.parametrize( - "time, index, span, expected", - [ - (np.arange(10.), 4, 2.0, (2.0, 6.0)), # Spans > 1 element +/- - (np.arange(10.), 2, 1.0, (1.0, 3.0)) # Spans = 1 element +/- - ] -) -def test_local_boundaries(time, index, span, expected): - actual = rp._local_boundaries(time, index, span) - assert expected == actual From 274ecc6d2f280bf58e1cfc24984c7a0d99a2cc59 Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Fri, 23 Apr 2021 17:40:13 -0700 Subject: [PATCH 008/234] Add tests for new DataFile and DataObject classes --- .../behavior/data_files/test_stimulus_file.py | 91 +++++ .../behavior/data_files/test_sync_file.py | 119 ++++++ .../behavior/data_objects/conftest.py | 24 ++ .../running_speed/test_running_acquisition.py | 313 ++++++++++++++++ .../running_speed/test_running_processing.py | 290 +++++++++++++++ .../running_speed/test_running_speed.py | 351 ++++++++++++++++++ .../test_stimulus_timestamps.py | 271 ++++++++++++++ .../test_timestamps_processing.py | 79 ++++ 8 files changed, 1538 insertions(+) create mode 100644 allensdk/test/brain_observatory/behavior/data_files/test_stimulus_file.py create mode 100644 allensdk/test/brain_observatory/behavior/data_files/test_sync_file.py create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/conftest.py create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_acquisition.py create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_processing.py create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_speed.py create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/stimulus_timestamps/test_stimulus_timestamps.py create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/stimulus_timestamps/test_timestamps_processing.py diff --git a/allensdk/test/brain_observatory/behavior/data_files/test_stimulus_file.py b/allensdk/test/brain_observatory/behavior/data_files/test_stimulus_file.py new file mode 100644 index 000000000..2ad42f8b7 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_files/test_stimulus_file.py @@ -0,0 +1,91 @@ +from typing import Tuple +from pathlib import Path +import pickle +from unittest.mock import create_autospec + +import pytest + +from allensdk.internal.api import PostgresQueryMixin +from allensdk.brain_observatory.behavior.data_files import StimulusFile + + +@pytest.fixture +def stimulus_file_fixture(request, tmp_path) -> Tuple[Path, dict]: + default_stim_pkl_data = {"a": 1, "b": 2, "c": 3} + stim_pkl_data = request.param.get("pkl_data", default_stim_pkl_data) + stim_pkl_filename = request.param.get("filename", "test_stimulus_file.pkl") + + stim_pkl_path = tmp_path / stim_pkl_filename + with stim_pkl_path.open('wb') as f: + pickle.dump(stim_pkl_data, f) + + return (stim_pkl_path, stim_pkl_data) + + +@pytest.mark.parametrize("stimulus_file_fixture", [ + ({"pkl_data": {"a": 42, "b": 7}}), + ({"pkl_data": {"slightly_more_complex": [1, 2, 3, 4]}}) +], indirect=["stimulus_file_fixture"]) +def test_stimulus_file_from_json(stimulus_file_fixture): + stim_pkl_path, stim_pkl_data = stimulus_file_fixture + + # Basic test case + input_json_dict = {"behavior_stimulus_file": str(stim_pkl_path)} + stimulus_file = StimulusFile.from_json(input_json_dict) + assert stimulus_file.data == stim_pkl_data + + # Now test caching by deleting the stimulus_file + stim_pkl_path.unlink() + stimulus_file_cached = StimulusFile.from_json(input_json_dict) + assert stimulus_file_cached.data == stim_pkl_data + + +@pytest.mark.parametrize("stimulus_file_fixture, behavior_session_id", [ + ({"pkl_data": {"a": 42, "b": 7}}, 12), + ({"pkl_data": {"slightly_more_complex": [1, 2, 3, 4]}}, 8) +], indirect=["stimulus_file_fixture"]) +def test_stimulus_file_from_lims(stimulus_file_fixture, behavior_session_id): + stim_pkl_path, stim_pkl_data = stimulus_file_fixture + + mock_db_conn = create_autospec(PostgresQueryMixin, instance=True) + + # Basic test case + mock_db_conn.fetchone.return_value = str(stim_pkl_path) + stimulus_file = StimulusFile.from_lims(mock_db_conn, behavior_session_id) + assert stimulus_file.data == stim_pkl_data + + # Now test caching by deleting stimulus_file and also asserting db + # `fetchone` called only once + stim_pkl_path.unlink() + stimfile_cached = StimulusFile.from_lims(mock_db_conn, behavior_session_id) + assert stimfile_cached.data == stim_pkl_data + + # This query string has strict formatting requirements + # in order to pass Mock assert_called_once_with() so don't change it! + query = f""" + SELECT + wkf.storage_directory || wkf.filename AS stim_file + FROM + well_known_files wkf + WHERE + wkf.attachable_id = {behavior_session_id} + AND wkf.attachable_type = 'BehaviorSession' + AND wkf.well_known_file_type_id IN ( + SELECT id + FROM well_known_file_types + WHERE name = 'StimulusPickle'); + """ + + mock_db_conn.fetchone.assert_called_once_with(query, strict=True) + + +@pytest.mark.parametrize("stimulus_file_fixture", [ + ({"filename": "test_stim_file_1.pkl"}), + ({"filename": "mock_stim_pkl_2.pkl"}) +], indirect=["stimulus_file_fixture"]) +def test_stimulus_file_to_json(stimulus_file_fixture): + stim_pkl_path, stim_pkl_data = stimulus_file_fixture + + stimulus_file = StimulusFile(filepath=stim_pkl_path) + obt_json = stimulus_file.to_json() + assert obt_json == {"behavior_stimulus_file": str(stim_pkl_path)} diff --git a/allensdk/test/brain_observatory/behavior/data_files/test_sync_file.py b/allensdk/test/brain_observatory/behavior/data_files/test_sync_file.py new file mode 100644 index 000000000..73ade1d89 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_files/test_sync_file.py @@ -0,0 +1,119 @@ +from typing import Tuple +from pathlib import Path +import h5py +from unittest.mock import create_autospec +import numpy as np + +import pytest + +from allensdk.internal.api import PostgresQueryMixin +from allensdk.brain_observatory.behavior.data_files import SyncFile + + +@pytest.fixture +def sync_file_fixture(request, tmp_path) -> Tuple[Path, dict]: + default_sync_data = [1, 2, 3, 4, 5] + sync_data = request.param.get("sync_data", default_sync_data) + sync_filename = request.param.get("filename", "test_sync_file.h5") + + sync_path = tmp_path / sync_filename + with h5py.File(sync_path, "w") as f: + f.create_dataset("data", data=sync_data) + + return (sync_path, sync_data) + + +def mock_get_sync_data(sync_path): + with h5py.File(sync_path, "r") as f: + data = f["data"][:] + return data + + +@pytest.mark.parametrize("sync_file_fixture", [ + ({"sync_data": [2, 3, 4, 5]}), +], indirect=["sync_file_fixture"]) +def test_sync_file_from_json(monkeypatch, sync_file_fixture): + sync_path, sync_data = sync_file_fixture + + with monkeypatch.context() as m: + m.setattr( + "allensdk.brain_observatory.behavior.data_files" + ".sync_file.get_sync_data", + mock_get_sync_data + ) + + # Basic test case + input_json_dict = {"sync_file": str(sync_path)} + sync_file = SyncFile.from_json(input_json_dict) + assert np.allclose(sync_file.data, sync_data) + + # Now test caching by deleting the sync_file + sync_path.unlink() + sync_file_cached = SyncFile.from_json(input_json_dict) + assert np.allclose(sync_file_cached.data, sync_data) + + +@pytest.mark.parametrize("sync_file_fixture, ophys_experiment_id", [ + ({"sync_data": [2, 3, 4, 5]}, 12), + ({"sync_data": [2, 3, 4, 5]}, 8) +], indirect=["sync_file_fixture"]) +def test_sync_file_from_lims( + monkeypatch, + sync_file_fixture, + ophys_experiment_id +): + sync_path, sync_data = sync_file_fixture + + mock_db_conn = create_autospec(PostgresQueryMixin, instance=True) + + with monkeypatch.context() as m: + m.setattr( + "allensdk.brain_observatory.behavior.data_files" + ".sync_file.get_sync_data", + mock_get_sync_data + ) + + # Basic test case + mock_db_conn.fetchone.return_value = str(sync_path) + sync_file = SyncFile.from_lims(mock_db_conn, ophys_experiment_id) + np.allclose(sync_file.data, sync_data) + + # Now test caching by deleting sync_file and also asserting db + # `fetchone` called only once + sync_path.unlink() + stimfile_cached = SyncFile.from_lims(mock_db_conn, ophys_experiment_id) + np.allclose(stimfile_cached.data, sync_data) + + # This query string has strict formatting requirements + # in order to pass Mock assert_called_once_with() so don't change it! + query = f""" + SELECT wkf.storage_directory || wkf.filename AS sync_file + FROM ophys_experiments oe + JOIN ophys_sessions os ON oe.ophys_session_id = os.id + JOIN well_known_files wkf ON wkf.attachable_id = os.id + JOIN well_known_file_types wkft + ON wkft.id = wkf.well_known_file_type_id + WHERE wkf.attachable_type = 'OphysSession' + AND wkft.name = 'OphysRigSync' + AND oe.id = {ophys_experiment_id}; + """ + + mock_db_conn.fetchone.assert_called_once_with(query, strict=True) + + +@pytest.mark.parametrize("sync_file_fixture", [ + ({"filename": "test_sync_file_1.h5"}), + ({"filename": "mock_sync_file_2.h5"}) +], indirect=["sync_file_fixture"]) +def test_sync_file_to_json(monkeypatch, sync_file_fixture): + sync_path, sync_data = sync_file_fixture + + with monkeypatch.context() as m: + m.setattr( + "allensdk.brain_observatory.behavior.data_files" + ".sync_file.get_sync_data", + mock_get_sync_data + ) + sync_file = SyncFile(filepath=sync_path) + obt_json = sync_file.to_json() + assert obt_json == {"sync_file": str(sync_path)} diff --git a/allensdk/test/brain_observatory/behavior/data_objects/conftest.py b/allensdk/test/brain_observatory/behavior/data_objects/conftest.py new file mode 100644 index 000000000..33a068bf7 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/conftest.py @@ -0,0 +1,24 @@ +import pynwb +import pytest + + +@pytest.fixture +def data_object_roundtrip_fixture(tmp_path): + def f(nwbfile, data_object_cls, **data_object_cls_kwargs): + tmp_dir = tmp_path / "data_object_nwb_roundtrip_tests" + tmp_dir.mkdir() + nwb_path = tmp_dir / "data_object_roundtrip_nwbfile.nwb" + + with pynwb.NWBHDF5IO(str(nwb_path), 'w') as write_io: + write_io.write(nwbfile) + + with pynwb.NWBHDF5IO(str(nwb_path), 'r') as read_io: + roundtripped_nwbfile = read_io.read() + + data_object_instance = data_object_cls.from_nwb( + roundtripped_nwbfile, **data_object_cls_kwargs + ) + + return data_object_instance + + return f diff --git a/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_acquisition.py b/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_acquisition.py new file mode 100644 index 000000000..94373114c --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_acquisition.py @@ -0,0 +1,313 @@ +import pytest +from unittest.mock import create_autospec + +import pandas as pd + +from allensdk.internal.api import PostgresQueryMixin +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects.running_speed.running_processing import ( # noqa: E501 + get_running_df +) +from allensdk.brain_observatory.behavior.data_objects import ( + RunningAcquisition, StimulusTimestamps +) + + +@pytest.mark.parametrize( + "dict_repr, returned_running_acq_df, expected_running_acq_df", + [ + ( + # dict_repr + { + "behavior_stimulus_file": "mock_stimulus_file.pkl" + }, + # returned_running_acq_df + pd.DataFrame( + { + "timestamps": [1, 2], + "speed": [3, 4], + "dx": [5, 6], + "v_sig": [7, 8], + "v_in": [9, 10] + } + ).set_index("timestamps"), + # expected_running_acq_df + pd.DataFrame( + { + "timestamps": [1, 2], + "dx": [5, 6], + "v_sig": [7, 8], + "v_in": [9, 10] + } + ).set_index("timestamps") + ), + ] +) +def test_running_acquisition_from_json( + monkeypatch, dict_repr, returned_running_acq_df, expected_running_acq_df +): + mock_stimulus_file = create_autospec(StimulusFile) + mock_stimulus_timestamps = create_autospec(StimulusTimestamps) + mock_get_running_df = create_autospec(get_running_df) + + mock_get_running_df.return_value = returned_running_acq_df + + with monkeypatch.context() as m: + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_acquisition.StimulusFile", + mock_stimulus_file + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_acquisition.StimulusTimestamps", + mock_stimulus_timestamps + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_acquisition.get_running_df", + mock_get_running_df + ) + obt = RunningAcquisition.from_json(dict_repr) + + mock_stimulus_file.from_json.assert_called_once_with(dict_repr) + mock_stimulus_file_instance = mock_stimulus_file.from_json(dict_repr) + assert obt._stimulus_file == mock_stimulus_file_instance + + mock_stimulus_timestamps.from_json.assert_called_once_with(dict_repr) + mock_stimulus_timestamps_instance = mock_stimulus_timestamps.from_json( + dict_repr + ) + assert obt._stimulus_timestamps == mock_stimulus_timestamps_instance + + mock_get_running_df.assert_called_once_with( + data=mock_stimulus_file_instance.data, + time=mock_stimulus_timestamps_instance.value, + ) + + pd.testing.assert_frame_equal(obt.value, expected_running_acq_df) + + +@pytest.mark.parametrize( + "stimulus_file, stimulus_file_to_json_ret, " + "stimulus_timestamps, stimulus_timestamps_to_json_ret, raises, expected", + [ + # Test to_json with both stimulus_file and sync_file + ( + # stimulus_file + create_autospec(StimulusFile, instance=True), + # stimulus_file_to_json_ret + {"behavior_stimulus_file": "stim.pkl"}, + # stimulus_timestamps + create_autospec(StimulusTimestamps, instance=True), + # stimulus_timestamps_to_json_ret + {"sync_file": "sync.h5"}, + # raises + False, + # expected + {"behavior_stimulus_file": "stim.pkl", "sync_file": "sync.h5"} + ), + # Test to_json without stimulus_file + ( + # stimulus_file + None, + # stimulus_file_to_json_ret + None, + # stimulus_timestamps + create_autospec(StimulusTimestamps, instance=True), + # stimulus_timestamps_to_json_ret + {"sync_file": "sync.h5"}, + # raises + "RunningAcquisition DataObject lacks information about", + # expected + None + ), + # Test to_json without stimulus_timestamps + ( + # stimulus_file + create_autospec(StimulusFile, instance=True), + # stimulus_file_to_json_ret + {"behavior_stimulus_file": "stim.pkl"}, + # stimulus_timestamps_to_json_ret + None, + # sync_file_to_json_ret + None, + # raises + "RunningAcquisition DataObject lacks information about", + # expected + None + ), + ] +) +def test_running_acquisition_to_json( + stimulus_file, stimulus_file_to_json_ret, + stimulus_timestamps, stimulus_timestamps_to_json_ret, raises, expected +): + if stimulus_file is not None: + stimulus_file.to_json.return_value = stimulus_file_to_json_ret + if stimulus_timestamps is not None: + stimulus_timestamps.to_json.return_value = ( + stimulus_timestamps_to_json_ret + ) + + running_acq = RunningAcquisition( + running_acquisition=None, + stimulus_file=stimulus_file, + stimulus_timestamps=stimulus_timestamps + ) + + if raises: + with pytest.raises(RuntimeError, match=raises): + _ = running_acq.to_json() + else: + obt = running_acq.to_json() + assert obt == expected + + +@pytest.mark.parametrize( + "behavior_session_id, ophys_experiment_id, " + "returned_running_acq_df, expected_running_acq_df", + [ + ( + # behavior_session_id + 12345, + # ophys_experiment_id + None, + # returned_running_acq_df + pd.DataFrame( + { + "timestamps": [1, 2], + "speed": [3, 4], + "dx": [5, 6], + "v_sig": [7, 8], + "v_in": [9, 10] + } + ).set_index("timestamps"), + # expected_running_acq_df + pd.DataFrame( + { + "timestamps": [1, 2], + "dx": [5, 6], + "v_sig": [7, 8], + "v_in": [9, 10] + } + ).set_index("timestamps") + ), + ( + # behavior_session_id + 1234, + # ophys_experiment_id + 5678, + # returned_running_acq_df + pd.DataFrame( + { + "timestamps": [2, 4], + "speed": [6, 8], + "dx": [10, 12], + "v_sig": [14, 16], + "v_in": [18, 20] + } + ).set_index("timestamps"), + # expected_running_acq_df + pd.DataFrame( + { + "timestamps": [2, 4], + "dx": [10, 12], + "v_sig": [14, 16], + "v_in": [18, 20] + } + ).set_index("timestamps") + ) + ] +) +def test_running_acquisition_from_lims( + monkeypatch, behavior_session_id, ophys_experiment_id, + returned_running_acq_df, expected_running_acq_df +): + mock_db_conn = create_autospec(PostgresQueryMixin, instance=True) + + mock_stimulus_file = create_autospec(StimulusFile) + mock_stimulus_timestamps = create_autospec(StimulusTimestamps) + mock_get_running_df = create_autospec(get_running_df) + + mock_get_running_df.return_value = returned_running_acq_df + + with monkeypatch.context() as m: + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_acquisition.StimulusFile", + mock_stimulus_file + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_acquisition.StimulusTimestamps", + mock_stimulus_timestamps + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_acquisition.get_running_df", + mock_get_running_df + ) + obt = RunningAcquisition.from_lims( + mock_db_conn, behavior_session_id, ophys_experiment_id + ) + + mock_stimulus_file.from_lims.assert_called_once_with( + mock_db_conn, behavior_session_id + ) + mock_stimulus_file_instance = mock_stimulus_file.from_lims( + mock_db_conn, behavior_session_id + ) + assert obt._stimulus_file == mock_stimulus_file_instance + + mock_stimulus_timestamps.from_lims.assert_called_once_with( + mock_db_conn, behavior_session_id, ophys_experiment_id + ) + mock_stimulus_timestamps_instance = mock_stimulus_timestamps.from_lims( + mock_db_conn, behavior_session_id, ophys_experiment_id + ) + assert obt._stimulus_timestamps == mock_stimulus_timestamps_instance + + mock_get_running_df.assert_called_once_with( + data=mock_stimulus_file_instance.data, + time=mock_stimulus_timestamps_instance.value, + ) + + pd.testing.assert_frame_equal( + obt.value, expected_running_acq_df, check_like=True + ) + + +# Fixtures: +# nwbfile: +# test/brain_observatory/behavior/conftest.py +# data_object_roundtrip_fixture: +# test/brain_observatory/behavior/data_objects/conftest.py +@pytest.mark.parametrize("roundtrip", [True, False]) +@pytest.mark.parametrize("running_acq_data", [ + ( + # expected_running_acq_df + pd.DataFrame( + { + "timestamps": [2.0, 4.0], + "dx": [10.0, 12.0], + "v_sig": [14.0, 16.0], + "v_in": [18.0, 20.0] + } + ).set_index("timestamps") + ), +]) +def test_running_acquisition_nwb_roundtrip( + nwbfile, data_object_roundtrip_fixture, roundtrip, running_acq_data +): + running_acq = RunningAcquisition(running_acquisition=running_acq_data) + nwbfile = running_acq.to_nwb(nwbfile) + + if roundtrip: + obt = data_object_roundtrip_fixture(nwbfile, RunningAcquisition) + else: + obt = RunningAcquisition.from_nwb(nwbfile) + + pd.testing.assert_frame_equal( + obt.value, running_acq_data, check_like=True + ) diff --git a/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_processing.py b/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_processing.py new file mode 100644 index 000000000..b06b263d7 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_processing.py @@ -0,0 +1,290 @@ +import numpy as np +import pytest + +from allensdk.brain_observatory.behavior.data_objects.running_speed.running_processing import ( # noqa: E501 + get_running_df, calc_deriv, deg_to_dist, _shift, _identify_wraps, + _unwrap_voltage_signal, _angular_change, _zscore_threshold_1d, + _clip_speed_wraps) + +import allensdk.brain_observatory.behavior.data_objects.running_speed.running_processing as rp # noqa: E501 + + +@pytest.fixture +def timestamps(): + return np.arange(0., 10., 0.1) + + +@pytest.fixture +def running_data(): + rng = np.random.default_rng() + return { + "items": { + "behavior": { + "encoders": [ + { + "dx": rng.random((100,)), + "vsig": rng.uniform(low=0.0, high=5.1, size=(100,)), + "vin": rng.uniform(low=4.9, high=5.0, size=(100,)), + }]}}} + + +@pytest.mark.parametrize( + "x,time,expected", [ + ([1.0, 1.0], [1.0, 2.0], [np.nan, 0.0]), + ([1.0, 2.0, 3.0], [1.0, 2.0, 3.0], [np.nan, 1.0, 1.0]), + ([1.0, 2.0, 3.0], [1.0, 4.0, 6.0], [np.nan, 1.0/3.0, 1.0/2.0]) + ] +) +def test_calc_deriv(x, time, expected): + obtained = calc_deriv(x, time) + + # np.nan == np.nan returns False so filter out the first values + obtained = obtained[1:] + expected = expected[1:] + + assert np.all(obtained == expected) + + +@pytest.mark.parametrize( + "speed,expected", [ + (np.array([1.0]), [5.5033]), + (np.array([0., 2.0]), [0., 11.0066]) + ] +) +def test_deg_to_dist(speed, expected): + np.testing.assert_allclose(deg_to_dist(speed), expected, atol=0.0001) + + +@pytest.mark.parametrize( + "lowpass", [True, False] +) +def test_get_running_df(running_data, timestamps, lowpass): + actual = get_running_df(running_data, timestamps, lowpass=lowpass) + np.testing.assert_array_equal(actual.index, timestamps) + assert sorted(list(actual)) == ["dx", "speed", "v_in", "v_sig"] + # Should bring raw data through + np.testing.assert_array_equal( + actual["v_sig"].values, + running_data["items"]["behavior"]["encoders"][0]["vsig"]) + np.testing.assert_array_equal( + actual["v_in"].values, + running_data["items"]["behavior"]["encoders"][0]["vin"]) + np.testing.assert_array_equal( + actual["dx"].values, + running_data["items"]["behavior"]["encoders"][0]["dx"]) + if lowpass: + assert np.count_nonzero(np.isnan(actual["speed"])) == 0 + + +@pytest.mark.parametrize( + "lowpass", [True, False] +) +def test_get_running_df_one_fewer_timestamp_check_warning(running_data, + timestamps, + lowpass): + with pytest.warns( + UserWarning, + match="Time array is 1 value shorter than encoder array.*" + ): + # Call with one fewer timestamp, check for a warning + _ = get_running_df( + data=running_data, + time=timestamps[:-1], + lowpass=lowpass + ) + + +@pytest.mark.parametrize( + "lowpass", [True, False] +) +def test_get_running_df_one_fewer_timestamp_check_truncation(running_data, + timestamps, + lowpass): + # Call with one fewer timestamp + output = get_running_df( + data=running_data, + time=timestamps[:-1], + lowpass=lowpass + ) + + # Check that the output is actually trimmed, and the values are the same + assert len(output) == len(timestamps) - 1 + np.testing.assert_equal( + output["v_sig"], + running_data["items"]["behavior"]["encoders"][0]["vsig"][:-1] + ) + np.testing.assert_equal( + output["v_in"], + running_data["items"]["behavior"]["encoders"][0]["vin"][:-1] + ) + + +@pytest.mark.parametrize( + "arr, periods, fill, expected", + [ + ([1, 2, 3], 1, None, np.array([np.nan, 1., 2.])), + ([1, 2, 3], 2, 99., np.array([99., 99., 1.])), + ([1, 2, 3], 3, 99., np.array([99., 99., 99.])), + ([1, 2, 3], 4, 99., np.array([99., 99., 99.])), + ([], 2, 30, np.array([])) + ] +) +def test_shift(arr, periods, fill, expected): + actual = _shift(arr, periods, fill) + np.testing.assert_array_equal(actual, expected) + + +@pytest.mark.parametrize( + "periods", [0, -2] +) +def test_shift_raises_error_periods_zero(periods): + with pytest.raises(ValueError, match="Can only shift"): + _shift(np.ones((5,)), periods) + + +@pytest.mark.parametrize( + "arr, min_threshold, max_threshold, expected", + [ + (np.array( + [0, 2, 5, 0, # pos wrap 5-0 + 2, 0, 5 # neg wrap 0-5 + ]), 1.5, 3.5, (np.array([3]), np.array([6]))), + (np.array([0, 2, 5, 0, 2, 5]), 0, 5, (np.array([]), np.array([]))), + ] +) +def test_identify_wraps(arr, min_threshold, max_threshold, expected): + actual = _identify_wraps( + arr, min_threshold=min_threshold, max_threshold=max_threshold) + np.testing.assert_array_equal( + actual[0], expected[0], + f"error identifying positive wraps, got {actual[0]}, " + f"expected {expected[0]}") + np.testing.assert_array_equal( + actual[1], expected[1], + f"error identifying negative wraps, got {actual[1]}, " + f"expected {expected[1]}") + + +@pytest.mark.parametrize( + "vsig, pos_wrap_ix, neg_wrap_ix, vmax, max_threshold, max_diff, expected", + [ + ( # No artifacts or baseline + np.array([0, 1, 3, 5, 0.5, 1, 2.5, 5, 0, 1, 4, 3]), + np.array([4, 8]), np.array([10]), 5.0, 5.1, 3.0, + np.array([np.nan, 1, 3, 5, 5.5, 6, 7.5, 10, 10, 11, 9, 8]) + ), + ( # Some diff artifacts, baseline + np.array([1, 1, 3, 5, 0.5, 1, 2.5, 5, 0, 1, 4, 1.5]), + np.array([4, 8]), np.array([10]), 5.0, 5.1, 2.0, + np.array([np.nan, 1, 3, 5, 5.5, 6, 7.5, np.nan, 7.5, 8.5, 6.5, + np.nan]) + ), + ( # Max artifact -- use threshold instead + np.array([0, 7, 3, 5, 0.5, 1]), + np.array([2, 4]), np.array([]).astype(int), None, 5.1, 6.0, + np.array([np.nan, np.nan, 1, 3, 3.5, 4]) + ), + ( + # No wraps + np.ones(5,), np.array([]), np.array([]), 5.0, 5.1, 3.0, + np.array([np.nan, 1., 1., 1., 1.]) + ) + ] +) +def test_unwrap_voltage_signal( + vsig, pos_wrap_ix, neg_wrap_ix, vmax, max_threshold, max_diff, + expected): + actual = _unwrap_voltage_signal( + vsig, pos_wrap_ix, neg_wrap_ix, vmax=vmax, + max_threshold=max_threshold, max_diff=max_diff) + np.testing.assert_array_equal(actual, expected) + + +@pytest.mark.parametrize( + "vsig, vmax, expected", + [ + ( + np.array([1, 2, 3, 4, 5]), 2.0, + np.array([np.nan, np.pi, np.pi, np.pi, np.pi]) + ), + ( + np.array([np.nan, 1, 3, np.nan, 4]), + np.array([2.0, 2.0, 2.0, 2.0, 2.0]), + np.array([np.nan, np.nan, 2*np.pi, np.nan, np.nan]), + ) + ] +) +def test_angular_change(vsig, vmax, expected): + actual = _angular_change(vsig, vmax) + np.testing.assert_allclose(actual, expected, equal_nan=True) + + +@pytest.mark.parametrize( + "arr, threshold, expected", + [ + (np.ones(5,), 2.0, np.ones(5,)), + (np.array([99, 1, np.nan, 1, 1, 1]), 1.5, + np.array([np.nan, 1, np.nan, 1, 1, 1])), + (np.ones(1,), 2.0, np.ones(1,)) + ] +) +def test_zscore_threshold_1d(arr, threshold, expected): + actual = _zscore_threshold_1d(arr, threshold=threshold) + np.testing.assert_allclose(actual, expected, equal_nan=True) + + +@pytest.mark.parametrize( + "speed, time, wrap_indices, span, expected", + [ + ( # Clip bottom, then clip top, then no clip required + np.array([0, 0, -1, 5, 0, 99, 6, 1, 2, 3]), + np.array(range(10)).astype(float), + [2, 5, 8], + 1.0, + np.array([0, 0, 0, 5, 0, 6, 6, 1, 2, 3]) + ), + ] +) +def test_clip_speed_wraps( + speed, time, wrap_indices, span, expected, monkeypatch): + monkeypatch.setattr(rp, "_local_boundaries", lambda x, y, z: (y-1, y+1)) + actual = _clip_speed_wraps(speed, time, wrap_indices, span) + np.testing.assert_array_equal(actual, expected) + + +@pytest.mark.parametrize( + "time, index, span", + [ + (np.arange(10.), 0, 2.0), # no neighborhood before first point + (np.arange(10.), 9, 2.0), # no neighborhood after last point + (np.arange(10.), 4, 0.25), # data not sampled with enough frequency + ] +) +def test_local_boundaries_raises_warning(time, index, span): + with pytest.warns(UserWarning, match="Unable to find"): + rp._local_boundaries(time, index, span) + + +@pytest.mark.parametrize( + "time, index", + [ + (np.array([5., 4., 3., 4., 5.]), 2), + (np.array([1., 2., 3., 2., 1.]), 2), + (np.array([3., 3., 3., 2., 1.]), 2), + ] +) +def test_local_boundaries_raises_error_non_monotonic(time, index): + with pytest.raises(ValueError, match="Data do not monotonically"): + rp._local_boundaries(time, index, 1.0) + + +@pytest.mark.parametrize( + "time, index, span, expected", + [ + (np.arange(10.), 4, 2.0, (2.0, 6.0)), # Spans > 1 element +/- + (np.arange(10.), 2, 1.0, (1.0, 3.0)) # Spans = 1 element +/- + ] +) +def test_local_boundaries(time, index, span, expected): + actual = rp._local_boundaries(time, index, span) + assert expected == actual diff --git a/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_speed.py b/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_speed.py new file mode 100644 index 000000000..f207cd542 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_speed.py @@ -0,0 +1,351 @@ +import pytest +from unittest.mock import create_autospec + +import pandas as pd + +from allensdk.core.exceptions import DataFrameIndexError +from allensdk.internal.api import PostgresQueryMixin +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects.running_speed.running_processing import ( # noqa: E501 + get_running_df +) +from allensdk.brain_observatory.behavior.data_objects import ( + RunningSpeed, StimulusTimestamps +) + + +@pytest.mark.parametrize("filtered", [True, False]) +@pytest.mark.parametrize("zscore_threshold", [1.0, 4.2]) +@pytest.mark.parametrize("returned_running_df, expected_running_df, raises", [ + # Test basic case + ( + # returned_running_df + pd.DataFrame({ + "timestamps": [2, 4, 6, 8], + "speed": [1, 2, 3, 4] + }).set_index("timestamps"), + # expected_running_df + pd.DataFrame({ + "timestamps": [2, 4, 6, 8], + "speed": [1, 2, 3, 4] + }), + # raises + False + ), + # Test when returned dataframe lacks "timestamps" as index + ( + # returned_running_df + pd.DataFrame({ + "timestamps": [2, 4, 6, 8], + "speed": [1, 2, 3, 4] + }).set_index("speed"), + # expected_running_df + None, + # raises + "Expected running_data_df index to be named 'timestamps'" + ), +]) +def test_get_running_speed_df( + monkeypatch, returned_running_df, filtered, zscore_threshold, + expected_running_df, raises +): + + mock_stimulus_file_instance = create_autospec(StimulusFile, instance=True) + mock_stimulus_timestamps_instance = create_autospec( + StimulusTimestamps, instance=True + ) + mock_get_running_speed_df = create_autospec(get_running_df) + mock_get_running_speed_df.return_value = returned_running_df + + with monkeypatch.context() as m: + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_speed.get_running_df", + mock_get_running_speed_df + ) + + if raises: + with pytest.raises(DataFrameIndexError, match=raises): + _ = RunningSpeed._get_running_speed_df( + mock_stimulus_file_instance, + mock_stimulus_timestamps_instance, + filtered, zscore_threshold + ) + else: + obt = RunningSpeed._get_running_speed_df( + mock_stimulus_file_instance, + mock_stimulus_timestamps_instance, + filtered, zscore_threshold + ) + + pd.testing.assert_frame_equal(obt, expected_running_df) + + mock_get_running_speed_df.assert_called_once_with( + data=mock_stimulus_file_instance.data, + time=mock_stimulus_timestamps_instance.value, + lowpass=filtered, + zscore_threshold=zscore_threshold + ) + + +@pytest.mark.parametrize("filtered", [True, False]) +@pytest.mark.parametrize("zscore_threshold", [1.0, 4.2]) +@pytest.mark.parametrize( + "dict_repr, returned_running_df, expected_running_df", + [ + ( + # dict_repr + { + "behavior_stimulus_file": "mock_stimulus_file.pkl" + }, + # returned_running_df + pd.DataFrame( + {"timestamps": [1, 2], "speed": [3, 4]} + ).set_index("timestamps"), + # expected_running_df + pd.DataFrame( + {"timestamps": [1, 2], "speed": [3, 4]} + ), + ), + ] +) +def test_running_speed_from_json( + monkeypatch, dict_repr, returned_running_df, expected_running_df, + filtered, zscore_threshold +): + mock_stimulus_file = create_autospec(StimulusFile) + mock_stimulus_timestamps = create_autospec(StimulusTimestamps) + mock_get_running_speed_df = create_autospec(get_running_df) + + mock_get_running_speed_df.return_value = returned_running_df + + with monkeypatch.context() as m: + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_speed.StimulusFile", + mock_stimulus_file + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_speed.StimulusTimestamps", + mock_stimulus_timestamps + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_speed.get_running_df", + mock_get_running_speed_df + ) + obt = RunningSpeed.from_json(dict_repr, filtered, zscore_threshold) + + mock_stimulus_file.from_json.assert_called_once_with(dict_repr) + mock_stimulus_file_instance = mock_stimulus_file.from_json(dict_repr) + assert obt._stimulus_file == mock_stimulus_file_instance + + mock_stimulus_timestamps.from_json.assert_called_once_with(dict_repr) + mock_stimulus_timestamps_instance = mock_stimulus_timestamps.from_json( + dict_repr + ) + assert obt._stimulus_timestamps == mock_stimulus_timestamps_instance + + mock_get_running_speed_df.assert_called_once_with( + data=mock_stimulus_file_instance.data, + time=mock_stimulus_timestamps_instance.value, + lowpass=filtered, + zscore_threshold=zscore_threshold + ) + + assert obt._filtered == filtered + pd.testing.assert_frame_equal(obt.value, expected_running_df) + + +@pytest.mark.parametrize( + "stimulus_file, stimulus_file_to_json_ret, " + "stimulus_timestamps, stimulus_timestamps_to_json_ret, raises, expected", + [ + # Test to_json with both stimulus_file and sync_file + ( + # stimulus_file + create_autospec(StimulusFile, instance=True), + # stimulus_file_to_json_ret + {"behavior_stimulus_file": "stim.pkl"}, + # stimulus_timestamps + create_autospec(StimulusTimestamps, instance=True), + # stimulus_timestamps_to_json_ret + {"sync_file": "sync.h5"}, + # raises + False, + # expected + {"behavior_stimulus_file": "stim.pkl", "sync_file": "sync.h5"} + ), + # Test to_json without stimulus_file + ( + # stimulus_file + None, + # stimulus_file_to_json_ret + None, + # stimulus_timestamps + create_autospec(StimulusTimestamps, instance=True), + # stimulus_timestamps_to_json_ret + {"sync_file": "sync.h5"}, + # raises + "RunningSpeed DataObject lacks information about", + # expected + None + ), + # Test to_json without stimulus_timestamps + ( + # stimulus_file + create_autospec(StimulusFile, instance=True), + # stimulus_file_to_json_ret + {"behavior_stimulus_file": "stim.pkl"}, + # stimulus_timestamps_to_json_ret + None, + # sync_file_to_json_ret + None, + # raises + "RunningSpeed DataObject lacks information about", + # expected + None + ), + ] +) +def test_running_speed_to_json( + stimulus_file, stimulus_file_to_json_ret, + stimulus_timestamps, stimulus_timestamps_to_json_ret, raises, expected +): + if stimulus_file is not None: + stimulus_file.to_json.return_value = stimulus_file_to_json_ret + if stimulus_timestamps is not None: + stimulus_timestamps.to_json.return_value = ( + stimulus_timestamps_to_json_ret + ) + + running_speed = RunningSpeed( + running_speed=None, + stimulus_file=stimulus_file, + stimulus_timestamps=stimulus_timestamps + ) + + if raises: + with pytest.raises(RuntimeError, match=raises): + _ = running_speed.to_json() + else: + obt = running_speed.to_json() + assert obt == expected + + +@pytest.mark.parametrize("behavior_session_id", [12345, 1234]) +@pytest.mark.parametrize("ophys_experiment_id", [None, 5678]) +@pytest.mark.parametrize("filtered", [True, False]) +@pytest.mark.parametrize("zscore_threshold", [1.0, 4.2]) +@pytest.mark.parametrize( + "returned_running_df, expected_running_df", + [ + ( + # returned_running_df + pd.DataFrame( + {"timestamps": [1, 2], "speed": [3, 4]} + ).set_index("timestamps"), + # expected_running_df + pd.DataFrame( + {"timestamps": [1, 2], "speed": [3, 4]} + ), + ), + ( + # returned_running_df + pd.DataFrame( + {"timestamps": [1, 2], "speed": [3, 4]} + ).set_index("timestamps"), + # expected_running_df + pd.DataFrame( + {"timestamps": [1, 2], "speed": [3, 4]} + ), + ) + ] +) +def test_running_speed_from_lims( + monkeypatch, behavior_session_id, ophys_experiment_id, returned_running_df, + expected_running_df, filtered, zscore_threshold +): + mock_db_conn = create_autospec(PostgresQueryMixin, instance=True) + + mock_stimulus_file = create_autospec(StimulusFile) + mock_stimulus_timestamps = create_autospec(StimulusTimestamps) + mock_get_running_speed_df = create_autospec(get_running_df) + mock_get_running_speed_df.return_value = returned_running_df + + with monkeypatch.context() as m: + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_speed.StimulusFile", + mock_stimulus_file + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_speed.StimulusTimestamps", + mock_stimulus_timestamps + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".running_speed.running_speed.get_running_df", + mock_get_running_speed_df + ) + obt = RunningSpeed.from_lims( + mock_db_conn, behavior_session_id, ophys_experiment_id, filtered, + zscore_threshold + ) + + mock_stimulus_file.from_lims.assert_called_once_with( + mock_db_conn, behavior_session_id + ) + mock_stimulus_file_instance = mock_stimulus_file.from_lims( + mock_db_conn, behavior_session_id + ) + assert obt._stimulus_file == mock_stimulus_file_instance + + mock_stimulus_timestamps.from_lims.assert_called_once_with( + mock_db_conn, behavior_session_id, ophys_experiment_id + ) + mock_stimulus_timestamps_instance = mock_stimulus_timestamps.from_lims( + mock_db_conn, behavior_session_id, ophys_experiment_id + ) + assert obt._stimulus_timestamps == mock_stimulus_timestamps_instance + + mock_get_running_speed_df.assert_called_once_with( + data=mock_stimulus_file_instance.data, + time=mock_stimulus_timestamps_instance.value, + lowpass=filtered, + zscore_threshold=zscore_threshold + ) + + assert obt._filtered == filtered + pd.testing.assert_frame_equal(obt.value, expected_running_df) + + +# Fixtures: +# nwbfile: +# test/brain_observatory/behavior/conftest.py +# data_object_roundtrip_fixture: +# test/brain_observatory/behavior/data_objects/conftest.py +@pytest.mark.parametrize("roundtrip", [True, False]) +@pytest.mark.parametrize("filtered", [True, False]) +@pytest.mark.parametrize("running_speed_data", [ + (pd.DataFrame({"timestamps": [3.0, 4.0], "speed": [5.0, 6.0]})), +]) +def test_running_speed_nwb_roundtrip( + nwbfile, data_object_roundtrip_fixture, roundtrip, running_speed_data, + filtered +): + running_speed = RunningSpeed( + running_speed=running_speed_data, filtered=filtered + ) + nwbfile = running_speed.to_nwb(nwbfile) + + if roundtrip: + obt = data_object_roundtrip_fixture( + nwbfile, RunningSpeed, filtered=filtered + ) + else: + obt = RunningSpeed.from_nwb(nwbfile, filtered=filtered) + + pd.testing.assert_frame_equal(obt.value, running_speed_data) diff --git a/allensdk/test/brain_observatory/behavior/data_objects/stimulus_timestamps/test_stimulus_timestamps.py b/allensdk/test/brain_observatory/behavior/data_objects/stimulus_timestamps/test_stimulus_timestamps.py new file mode 100644 index 000000000..f53e381f1 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/stimulus_timestamps/test_stimulus_timestamps.py @@ -0,0 +1,271 @@ +import pytest +from unittest.mock import create_autospec + +import numpy as np + +from allensdk.internal.api import PostgresQueryMixin +from allensdk.brain_observatory.behavior.data_files import ( + StimulusFile, SyncFile +) +from allensdk.brain_observatory.behavior.data_objects.stimulus_timestamps.timestamps_processing import ( # noqa: E501 + get_behavior_stimulus_timestamps, get_ophys_stimulus_timestamps +) +from allensdk.brain_observatory.behavior.data_objects import StimulusTimestamps + + +@pytest.mark.parametrize("dict_repr, has_pkl, has_sync", [ + # Test where input json only has "behavior_stimulus_file" + ( + # dict_repr + { + "behavior_stimulus_file": "mock_stimulus_file.pkl" + }, + # has_pkl + True, + # has_sync + False + ), + # Test where input json has both "behavior_stimulus_file" and "sync_file" + ( + # dict_repr + { + "behavior_stimulus_file": "mock_stimulus_file.pkl", + "sync_file": "mock_sync_file.h5" + }, + # has_pkl + True, + # has_sync + True + ), +]) +def test_stimulus_timestamps_from_json( + monkeypatch, dict_repr, has_pkl, has_sync +): + mock_stimulus_file = create_autospec(StimulusFile) + mock_sync_file = create_autospec(SyncFile) + + mock_get_behavior_stimulus_timestamps = create_autospec( + get_behavior_stimulus_timestamps + ) + mock_get_ophys_stimulus_timestamps = create_autospec( + get_ophys_stimulus_timestamps + ) + + with monkeypatch.context() as m: + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".stimulus_timestamps.stimulus_timestamps.StimulusFile", + mock_stimulus_file + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".stimulus_timestamps.stimulus_timestamps.SyncFile", + mock_sync_file + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".stimulus_timestamps.stimulus_timestamps" + ".get_behavior_stimulus_timestamps", + mock_get_behavior_stimulus_timestamps + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".stimulus_timestamps.stimulus_timestamps" + ".get_ophys_stimulus_timestamps", + mock_get_ophys_stimulus_timestamps + ) + obt = StimulusTimestamps.from_json(dict_repr) + + mock_stimulus_file.from_json.assert_called_with(dict_repr) + mock_stimulus_file_instance = mock_stimulus_file.from_json(dict_repr) + assert obt._stimulus_file == mock_stimulus_file_instance + + if has_pkl and has_sync: + mock_sync_file.from_json.assert_called_with(dict_repr) + mock_sync_file_instance = mock_sync_file.from_json(dict_repr) + mock_get_ophys_stimulus_timestamps.assert_called_once_with( + sync_path=mock_sync_file_instance.filepath + ) + assert obt._sync_file == mock_sync_file_instance + else: + mock_get_behavior_stimulus_timestamps.assert_called_once_with( + stimulus_pkl=mock_stimulus_file_instance.data + ) + + +@pytest.mark.parametrize( + "stimulus_file, stimulus_file_to_json_ret, " + "sync_file, sync_file_to_json_ret, raises, expected", + [ + # Test to_json with both stimulus_file and sync_file + ( + # stimulus_file + create_autospec(StimulusFile, instance=True), + # stimulus_file_to_json_ret + {"behavior_stimulus_file": "stim.pkl"}, + # sync_file + create_autospec(SyncFile, instance=True), + # sync_file_to_json_ret + {"sync_file": "sync.h5"}, + # raises + False, + # expected + {"behavior_stimulus_file": "stim.pkl", "sync_file": "sync.h5"} + ), + # Test to_json with only stimulus_file + ( + # stimulus_file + create_autospec(StimulusFile, instance=True), + # stimulus_file_to_json_ret + {"behavior_stimulus_file": "stim.pkl"}, + # sync_file + None, + # sync_file_to_json_ret + None, + # raises + False, + # expected + {"behavior_stimulus_file": "stim.pkl"} + ), + # Test to_json without stimulus_file nor sync_file + ( + # stimulus_file + None, + # stimulus_file_to_json_ret + None, + # sync_file + None, + # sync_file_to_json_ret + None, + # raises + "StimulusTimestamps DataObject lacks information about", + # expected + None + ), + ] +) +def test_stimulus_timestamps_to_json( + stimulus_file, stimulus_file_to_json_ret, + sync_file, sync_file_to_json_ret, raises, expected +): + if stimulus_file is not None: + stimulus_file.to_json.return_value = stimulus_file_to_json_ret + if sync_file is not None: + sync_file.to_json.return_value = sync_file_to_json_ret + + stimulus_timestamps = StimulusTimestamps( + timestamps=None, + stimulus_file=stimulus_file, + sync_file=sync_file + ) + + if raises: + with pytest.raises(RuntimeError, match=raises): + _ = stimulus_timestamps.to_json() + else: + obt = stimulus_timestamps.to_json() + assert obt == expected + + +@pytest.mark.parametrize("behavior_session_id, ophys_experiment_id", [ + ( + 12345, + None + ), + ( + 1234, + 5678 + ) +]) +def test_stimulus_timestamps_from_lims( + monkeypatch, behavior_session_id, ophys_experiment_id +): + mock_db_conn = create_autospec(PostgresQueryMixin, instance=True) + + mock_stimulus_file = create_autospec(StimulusFile) + mock_sync_file = create_autospec(SyncFile) + + mock_get_behavior_stimulus_timestamps = create_autospec( + get_behavior_stimulus_timestamps + ) + mock_get_ophys_stimulus_timestamps = create_autospec( + get_ophys_stimulus_timestamps + ) + + with monkeypatch.context() as m: + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".stimulus_timestamps.stimulus_timestamps.StimulusFile", + mock_stimulus_file + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".stimulus_timestamps.stimulus_timestamps.SyncFile", + mock_sync_file + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".stimulus_timestamps.stimulus_timestamps" + ".get_behavior_stimulus_timestamps", + mock_get_behavior_stimulus_timestamps + ) + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".stimulus_timestamps.stimulus_timestamps" + ".get_ophys_stimulus_timestamps", + mock_get_ophys_stimulus_timestamps + ) + obt = StimulusTimestamps.from_lims( + mock_db_conn, behavior_session_id, ophys_experiment_id + ) + + mock_stimulus_file.from_lims.assert_called_with( + mock_db_conn, behavior_session_id + ) + mock_stimulus_file_instance = mock_stimulus_file.from_lims( + mock_db_conn, behavior_session_id + ) + assert obt._stimulus_file == mock_stimulus_file_instance + + if behavior_session_id is not None and ophys_experiment_id is not None: + mock_sync_file.from_lims.assert_called_with( + mock_db_conn, ophys_experiment_id + ) + mock_sync_file_instance = mock_sync_file.from_lims( + mock_db_conn, ophys_experiment_id + ) + mock_get_ophys_stimulus_timestamps.assert_called_once_with( + sync_path=mock_sync_file_instance.filepath + ) + assert obt._sync_file == mock_sync_file_instance + else: + mock_get_behavior_stimulus_timestamps.assert_called_once_with( + stimulus_pkl=mock_stimulus_file_instance.data + ) + + +# Fixtures: +# nwbfile: +# test/brain_observatory/behavior/conftest.py +# data_object_roundtrip_fixture: +# test/brain_observatory/behavior/data_objects/conftest.py +@pytest.mark.parametrize('roundtrip, stimulus_timestamps_data', [ + (True, np.array([1, 2, 3, 4, 5])), + (True, np.array([6, 7, 8, 9, 10])), + (False, np.array([11, 12, 13, 14, 15])), + (False, np.array([16, 17, 18, 19, 20])) +]) +def test_stimulus_timestamps_nwb_roundtrip( + nwbfile, data_object_roundtrip_fixture, roundtrip, stimulus_timestamps_data +): + stimulus_timestamps = StimulusTimestamps( + timestamps=stimulus_timestamps_data + ) + nwbfile = stimulus_timestamps.to_nwb(nwbfile) + + if roundtrip: + obt = data_object_roundtrip_fixture(nwbfile, StimulusTimestamps) + else: + obt = StimulusTimestamps.from_nwb(nwbfile) + + assert np.allclose(obt.value, stimulus_timestamps_data) diff --git a/allensdk/test/brain_observatory/behavior/data_objects/stimulus_timestamps/test_timestamps_processing.py b/allensdk/test/brain_observatory/behavior/data_objects/stimulus_timestamps/test_timestamps_processing.py new file mode 100644 index 000000000..db4e382e6 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/stimulus_timestamps/test_timestamps_processing.py @@ -0,0 +1,79 @@ +from unittest.mock import create_autospec, PropertyMock + +import pytest +import numpy as np + +from allensdk.brain_observatory.behavior.data_objects.stimulus_timestamps.timestamps_processing import ( # noqa: E501 + get_behavior_stimulus_timestamps, get_ophys_stimulus_timestamps +) +from allensdk.internal.brain_observatory.time_sync import OphysTimeAligner + + +@pytest.mark.parametrize("pkl_data, expected", [ + # Extremely basic test case + ( + # pkl_data + { + "items": { + "behavior": { + "intervalsms": np.array([ + 1000, 1001, 1002, 1003, 1004, 1005 + ]) + } + } + }, + # expected + np.array([ + 0.0, 1.0, 2.001, 3.003, 4.006, 5.01, 6.015 + ]) + ), + # More realistic test case + ( + # pkl_data + { + "items": { + "behavior": { + "intervalsms": np.array([ + 16.5429, 16.6685, 16.66580001, 16.70569999, 16.6668, + 16.69619999, 16.655, 16.6805, 16.75940001, 16.6831 + ]) + } + } + }, + # expected + np.array([ + 0.0, 0.0165429, 0.0332114, 0.0498772, 0.0665829, 0.0832497, + 0.0999459, 0.1166009, 0.1332814, 0.1500408, 0.1667239 + ]) + ) +]) +def test_get_behavior_stimulus_timestamps(pkl_data, expected): + obt = get_behavior_stimulus_timestamps(pkl_data) + assert np.allclose(obt, expected) + + +@pytest.mark.parametrize("sync_path, expected_timestamps", [ + ("/tmp/mock_sync_file.h5", [1, 2, 3]), +]) +def test_get_ophys_stimulus_timestamps( + monkeypatch, sync_path, expected_timestamps +): + + mock_ophys_time_aligner = create_autospec(OphysTimeAligner) + mock_aligner_instance = mock_ophys_time_aligner.return_value + property_mock = PropertyMock( + return_value=(expected_timestamps, "ignored_return_val") + ) + type(mock_aligner_instance).clipped_stim_timestamps = property_mock + + with monkeypatch.context() as m: + m.setattr( + "allensdk.brain_observatory.behavior.data_objects" + ".stimulus_timestamps.timestamps_processing.OphysTimeAligner", + mock_ophys_time_aligner + ) + obt = get_ophys_stimulus_timestamps(sync_path) + + mock_ophys_time_aligner.assert_called_with(sync_file=sync_path) + property_mock.assert_called_once() + assert np.allclose(obt, expected_timestamps) From dc626787fce350e3f0b8136e175edc6abe1212a9 Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Mon, 26 Apr 2021 10:05:21 -0700 Subject: [PATCH 009/234] Fix running_processing import bug --- .../session_apis/data_transforms/behavior_data_transforms.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py b/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py index 6fa8c19a4..daf8ed43a 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py @@ -10,8 +10,9 @@ from allensdk.api.warehouse_cache.cache import memoize from allensdk.internal.core.lims_utilities import safe_system_path from allensdk.brain_observatory.behavior.rewards_processing import get_rewards -from allensdk.brain_observatory.behavior.running_processing import \ +from allensdk.brain_observatory.behavior.data_objects.running_speed.running_processing import ( # noqa: E501 get_running_df +) from allensdk.brain_observatory.behavior.session_apis.abcs.\ session_base.behavior_base import BehaviorBase from allensdk.brain_observatory.behavior.session_apis.abcs.\ From 1bb32e74e141ed3a06ad972cd71237a246086b62 Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Mon, 26 Apr 2021 16:50:16 -0700 Subject: [PATCH 010/234] Add BehaviorSessionId DataObject --- .../behavior/data_objects/__init__.py | 1 + .../data_objects/behavior_session_id.py | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 allensdk/brain_observatory/behavior/data_objects/behavior_session_id.py diff --git a/allensdk/brain_observatory/behavior/data_objects/__init__.py b/allensdk/brain_observatory/behavior/data_objects/__init__.py index 1d1eaf7fe..7ae413984 100644 --- a/allensdk/brain_observatory/behavior/data_objects/__init__.py +++ b/allensdk/brain_observatory/behavior/data_objects/__init__.py @@ -1,4 +1,5 @@ from allensdk.brain_observatory.behavior.data_objects._data_object_abc import DataObject # noqa: E501, F401 +from allensdk.brain_observatory.behavior.data_objects.behavior_session_id import BehaviorSessionId # noqa: E501, F401 from allensdk.brain_observatory.behavior.data_objects.stimulus_timestamps.stimulus_timestamps import StimulusTimestamps # noqa: E501, F401 from allensdk.brain_observatory.behavior.data_objects.running_speed.running_speed import RunningSpeed # noqa: E501, F401 from allensdk.brain_observatory.behavior.data_objects.running_speed.running_acquisition import RunningAcquisition # noqa: E501, F401 diff --git a/allensdk/brain_observatory/behavior/data_objects/behavior_session_id.py b/allensdk/brain_observatory/behavior/data_objects/behavior_session_id.py new file mode 100644 index 000000000..6c9e0e1ca --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/behavior_session_id.py @@ -0,0 +1,54 @@ +from pynwb import NWBFile + +from cachetools import cached, LRUCache +from cachetools.keys import hashkey + +from allensdk.internal.api import PostgresQueryMixin +from allensdk.brain_observatory.behavior.data_objects import DataObject + + +def from_lims_cache_key(cls, db, ophys_experiment_id: int): + return hashkey(ophys_experiment_id) + + +class BehaviorSessionId(DataObject): + def __init__(self, behavior_session_id: int): + super().__init__(name="behavior_session_id", value=behavior_session_id) + + @classmethod + def from_json(cls, dict_repr: dict) -> "BehaviorSessionId": + return cls(behavior_session_id=dict_repr["behavior_session_id"]) + + def to_json(self) -> dict: + return {"behavior_session_id": self.value} + + @classmethod + @cached(cache=LRUCache(maxsize=10), key=from_lims_cache_key) + def from_lims( + cls, db: PostgresQueryMixin, + ophys_experiment_id: int + ) -> "BehaviorSessionId": + query = f""" + SELECT bs.id + FROM ophys_experiments oe + -- every ophys_experiment should have an ophys_session + JOIN ophys_sessions os ON oe.ophys_session_id = os.id + JOIN behavior_sessions bs ON os.id = bs.ophys_session_id + WHERE oe.id = {ophys_experiment_id}; + """ + behavior_session_id = db.fetchone(query, strict=True) + return cls(behavior_session_id=behavior_session_id) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorSessionId": + # TODO: + # This implementation will be wrong when trying to get + # behavior session id for an ophys experiment. + # Will need to revisit. + return cls(behavior_session_id=int(nwbfile.identifier)) + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + # TODO: + # Likely need to have some yet to be determined interaction with + # the out-of-scope `metadata` DataObject + raise NotImplementedError From 234a2a043ba2a98fcd95e0c9bd2b0b4168491110 Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Wed, 28 Apr 2021 08:12:30 -0700 Subject: [PATCH 011/234] Use new DataObject classes with existing BehaviorSession --- .../behavior/behavior_session.py | 112 ++++++++++++++---- .../session_apis/data_io/behavior_nwb_api.py | 96 ++------------- .../behavior/write_behavior_nwb/__main__.py | 13 +- .../brain_observatory/session_api_utils.py | 10 +- 4 files changed, 116 insertions(+), 115 deletions(-) diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index 88f3d3741..a278e2ffc 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -1,5 +1,6 @@ from typing import Any, Optional, List, Dict, Type, Tuple import logging +import pynwb import pandas as pd import numpy as np import inspect @@ -9,38 +10,49 @@ from allensdk.core.lazy_property import LazyPropertyMixin from allensdk.brain_observatory.session_api_utils import ParamsMixin from allensdk.brain_observatory.behavior.session_apis.data_io import ( - BehaviorLimsApi, BehaviorNwbApi) + BehaviorNwbApi, BehaviorJsonApi, BehaviorLimsApi) from allensdk.brain_observatory.behavior.session_apis.abcs.\ session_base.behavior_base import BehaviorBase from allensdk.brain_observatory.behavior.trials_processing import ( construct_rolling_performance_df, calculate_reward_rate_fix_nans) +from allensdk.brain_observatory.behavior.data_objects import ( + BehaviorSessionId, StimulusTimestamps, RunningSpeed, RunningAcquisition +) + +from allensdk.core.auth_config import LIMS_DB_CREDENTIAL_MAP +from allensdk.internal.api import db_connection_creator BehaviorDataApi = Type[BehaviorBase] class BehaviorSession(LazyPropertyMixin): - def __init__(self, api: Optional[BehaviorDataApi] = None): + def __init__( + self, api: Optional[BehaviorDataApi] = None, + behavior_session_id: BehaviorSessionId = None, + stimulus_timestamps: StimulusTimestamps = None, + running_acquisition: RunningAcquisition = None, + raw_running_speed: RunningSpeed = None, + running_speed: RunningSpeed = None, + ): self.api = api # LazyProperty constructor provided by LazyPropertyMixin LazyProperty = self.LazyProperty # Initialize attributes to be lazily evaluated - self._behavior_session_id = LazyProperty( - self.api.get_behavior_session_id) + self._behavior_session_id = behavior_session_id self._licks = LazyProperty(self.api.get_licks, settable=True) self._rewards = LazyProperty(self.api.get_rewards, settable=True) - self._running_speed = LazyProperty(self.api.get_running_speed, - settable=True, lowpass=True) - self._raw_running_speed = LazyProperty(self.api.get_running_speed, - settable=True, lowpass=False) + self._running_acquisition = running_acquisition + self._running_speed = running_speed + self._raw_running_speed = raw_running_speed self._stimulus_presentations = LazyProperty( self.api.get_stimulus_presentations, settable=True) self._stimulus_templates = LazyProperty( - self.api.get_stimulus_templates, settable=True) - self._stimulus_timestamps = LazyProperty( - self.api.get_stimulus_timestamps, settable=True) + self.api.get_stimulus_templates, settable=True + ) + self._stimulus_timestamps = stimulus_timestamps self._task_parameters = LazyProperty(self.api.get_task_parameters, settable=True) self._trials = LazyProperty(self.api.get_trials, settable=True) @@ -48,14 +60,71 @@ def __init__(self, api: Optional[BehaviorDataApi] = None): # ==================== class and utility methods ====================== + @classmethod + def from_json(cls, session_data: dict) -> "BehaviorSession": + behavior_session_id = BehaviorSessionId.from_json(session_data) + stimulus_timestamps = StimulusTimestamps.from_json(session_data) + running_acquisition = RunningAcquisition.from_json(session_data) + raw_running_speed = RunningSpeed.from_json( + session_data, filtered=False + ) + running_speed = RunningSpeed.from_json(session_data) + return cls( + api=BehaviorJsonApi(session_data), + behavior_session_id=behavior_session_id, + stimulus_timestamps=stimulus_timestamps, + running_acquisition=running_acquisition, + raw_running_speed=raw_running_speed, + running_speed=running_speed + ) + @classmethod def from_lims(cls, behavior_session_id: int) -> "BehaviorSession": - return cls(api=BehaviorLimsApi(behavior_session_id)) + lims_db = db_connection_creator( + fallback_credentials=LIMS_DB_CREDENTIAL_MAP + ) + + behavior_session_id = BehaviorSessionId(behavior_session_id) + stimulus_timestamps = StimulusTimestamps.from_lims( + lims_db, behavior_session_id.value + ) + running_acquisition = RunningAcquisition.from_lims( + lims_db, behavior_session_id.value + ) + raw_running_speed = RunningSpeed.from_lims( + lims_db, behavior_session_id.value, filtered=False + ) + running_speed = RunningSpeed.from_lims( + lims_db, behavior_session_id.value + ) + return cls( + api=BehaviorLimsApi(behavior_session_id.value), + behavior_session_id=behavior_session_id, + stimulus_timestamps=stimulus_timestamps, + running_acquisition=running_acquisition, + raw_running_speed=raw_running_speed, + running_speed=running_speed + ) @classmethod def from_nwb_path( - cls, nwb_path: str, **api_kwargs: Any) -> "BehaviorSession": - return cls(api=BehaviorNwbApi.from_path(path=nwb_path, **api_kwargs)) + cls, nwb_path: str, **api_kwargs: Any + ) -> "BehaviorSession": + with pynwb.NWBHDF5IO(str(nwb_path), 'r') as read_io: + nwbfile = read_io.read() + behavior_session_id = BehaviorSessionId.from_nwb(nwbfile) + stimulus_timestamps = StimulusTimestamps.from_nwb(nwbfile) + running_acquisition = RunningAcquisition.from_nwb(nwbfile) + raw_running_speed = RunningSpeed.from_nwb(nwbfile, filtered=False) + running_speed = RunningSpeed.from_nwb(nwbfile) + return cls( + api=BehaviorNwbApi.from_path(path=nwb_path, **api_kwargs), + behavior_session_id=behavior_session_id, + stimulus_timestamps=stimulus_timestamps, + running_acquisition=running_acquisition, + raw_running_speed=raw_running_speed, + running_speed=running_speed + ) def cache_clear(self) -> None: """Convenience method to clear the api cache, if applicable.""" @@ -95,6 +164,7 @@ def list_data_attributes_and_methods(self) -> List[str]: attrs_and_methods_to_ignore: set = { "api", "cache_clear", + "from_json", "from_lims", "from_nwb_path", "LazyProperty", @@ -309,7 +379,7 @@ def behavior_session_id(self) -> int: """Unique identifier for a behavioral session. :rtype: int """ - return self._behavior_session_id + return self._behavior_session_id.value @property def licks(self) -> pd.DataFrame: @@ -393,11 +463,11 @@ def running_speed(self) -> pd.DataFrame: speed: (float) speed in cm/sec """ - return self._running_speed + return self._running_speed.value @running_speed.setter def running_speed(self, value): - self._running_speed = value + self._running_speed.value = value @property def raw_running_speed(self) -> pd.DataFrame: @@ -418,11 +488,11 @@ def raw_running_speed(self) -> pd.DataFrame: speed: (float) speed in cm/sec """ - return self._raw_running_speed + return self._raw_running_speed.value @raw_running_speed.setter def raw_running_speed(self, value): - self._raw_running_speed = value + self._raw_running_speed.value = value @property def stimulus_presentations(self) -> pd.DataFrame: @@ -511,11 +581,11 @@ def stimulus_timestamps(self) -> np.ndarray: np.ndarray Timestamps associated with stimulus presentations on the monitor """ - return self._stimulus_timestamps + return self._stimulus_timestamps.value @stimulus_timestamps.setter def stimulus_timestamps(self, value): - self._stimulus_timestamps = value + self._stimulus_timestamps.value = value @property def task_parameters(self) -> dict: diff --git a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py index 637a4704f..364e5974a 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py @@ -57,25 +57,16 @@ def save(self, session_object): ) # Add stimulus_timestamps to NWB in-memory object: - nwb.add_stimulus_timestamps(nwbfile, - session_object.stimulus_timestamps) + session_object._stimulus_timestamps.to_nwb(nwbfile) # Add running acquisition ('dx', 'v_sig', 'v_in') data to NWB # This data should be saved to NWB but not accessible directly from # Sessions - nwb.add_running_acquisition_to_nwbfile( - nwbfile, - session_object.api.get_running_acquisition_df()) + session_object._running_acquisition.to_nwb(nwbfile) # Add running data to NWB in-memory object: - nwb.add_running_speed_to_nwbfile(nwbfile, - session_object.running_speed, - name="speed", - from_dataframe=True) - nwb.add_running_speed_to_nwbfile(nwbfile, - session_object.raw_running_speed, - name="speed_unfiltered", - from_dataframe=True) + session_object._raw_running_speed.to_nwb(nwbfile) + session_object._running_speed.to_nwb(nwbfile) # Add stimulus template data to NWB in-memory object: # Use the semi-private _stimulus_templates attribute because it is @@ -125,75 +116,11 @@ def get_behavior_session_id(self) -> int: self.get_metadata() return self._behavior_session_id - def get_running_acquisition_df(self) -> pd.DataFrame: - """Get running speed acquisition data. - - Returns - ------- - pd.DataFrame - Dataframe with an index of timestamps and the following columns: - "dx": angular change, computed during data collection - "v_sig": voltage signal from the encoder - "v_in": the theoretical maximum voltage that the encoder - will reach prior to "wrapping". This should - theoretically be 5V (after crossing 5V goes to 0V, or - vice versa). In practice the encoder does not always - reach this value before wrapping, which can cause - transient spikes in speed at the voltage "wraps". - """ - running_module = self.nwbfile.modules['running'] - dx_interface = running_module.get_data_interface('dx') - - timestamps = dx_interface.timestamps[:] - dx = dx_interface.data - v_in = self.nwbfile.get_acquisition('v_in').data - v_sig = self.nwbfile.get_acquisition('v_sig').data - - running_acq_df = pd.DataFrame( - { - 'dx': dx, - 'v_in': v_in, - 'v_sig': v_sig - }, - index=pd.Index(timestamps, name='timestamps')) - - return running_acq_df - - def get_running_speed(self, lowpass: bool = True) -> pd.DataFrame: - """ - Gets running speed data - - NOTE: Overrides the inherited method from: - allensdk.brain_observatory.nwb.nwb_api - - Parameters - ---------- - lowpass: bool - Whether to return running speed with or without low pass filter - applied - zscore_threshold: float - The threshold to use for removing outlier running speeds which - might be noise and not true signal - - Returns - ------- - pd.DataFrame: - Dataframe containing various signals used to compute running - speed, and the filtered or unfiltered speed. - """ - running_module = self.nwbfile.modules['running'] - interface_name = 'speed' if lowpass else 'speed_unfiltered' - running_interface = running_module.get_data_interface(interface_name) - values = running_interface.data[:] - timestamps = running_interface.timestamps[:] - - running_speed_df = pd.DataFrame( - { - 'timestamps': timestamps, - 'speed': values - }, - ) - return running_speed_df + def get_running_acquisition_df(self): + raise NotImplementedError() + + def get_running_speed(self): + raise NotImplementedError() def get_stimulus_templates(self, **kwargs) -> Optional[StimulusTemplate]: @@ -217,9 +144,8 @@ def get_stimulus_presentations(self) -> pd.DataFrame: df['is_change'] = is_change_event(stimulus_presentations=df) return df - def get_stimulus_timestamps(self) -> np.ndarray: - stim_module = self.nwbfile.processing['stimulus'] - return stim_module.get_data_interface('timestamps').timestamps[:] + def get_stimulus_timestamps(self): + raise NotImplementedError def get_trials(self) -> pd.DataFrame: trials = self.nwbfile.trials.to_dataframe() diff --git a/allensdk/brain_observatory/behavior/write_behavior_nwb/__main__.py b/allensdk/brain_observatory/behavior/write_behavior_nwb/__main__.py index ff0263282..057988e44 100644 --- a/allensdk/brain_observatory/behavior/write_behavior_nwb/__main__.py +++ b/allensdk/brain_observatory/behavior/write_behavior_nwb/__main__.py @@ -7,7 +7,7 @@ from allensdk.brain_observatory.behavior.behavior_session import ( BehaviorSession) from allensdk.brain_observatory.behavior.session_apis.data_io import ( - BehaviorNwbApi, BehaviorJsonApi, BehaviorLimsApi) + BehaviorNwbApi) from allensdk.brain_observatory.behavior.write_behavior_nwb._schemas import ( InputSchema, OutputSchema) from allensdk.brain_observatory.argschema_utilities import ( @@ -28,10 +28,10 @@ def write_behavior_nwb(session_data, nwb_filepath): os.remove(filename) try: - json_session = BehaviorSession(api=BehaviorJsonApi(session_data)) - lims_api = BehaviorLimsApi( - behavior_session_id=session_data['behavior_session_id']) - lims_session = BehaviorSession(api=lims_api) + json_session = BehaviorSession.from_json(session_data) + + behavior_session_id = session_data['behavior_session_id'] + lims_session = BehaviorSession.from_lims(behavior_session_id) logging.info("Comparing a BehaviorSession created from JSON " "with a BehaviorSession created from LIMS") @@ -41,8 +41,7 @@ def write_behavior_nwb(session_data, nwb_filepath): logging.info("Comparing a BehaviorSession created from JSON " "with a BehaviorSession created from NWB") - nwb_api = BehaviorNwbApi(nwb_filepath_inprogress) - nwb_session = BehaviorSession(api=nwb_api) + nwb_session = BehaviorSession.from_nwb_path(nwb_filepath_inprogress) assert sessions_are_equal(json_session, nwb_session, reraise=True) os.rename(nwb_filepath_inprogress, nwb_filepath) diff --git a/allensdk/brain_observatory/session_api_utils.py b/allensdk/brain_observatory/session_api_utils.py index 45dbff91d..c46b034b3 100644 --- a/allensdk/brain_observatory/session_api_utils.py +++ b/allensdk/brain_observatory/session_api_utils.py @@ -15,6 +15,8 @@ from pandas.util.testing import assert_frame_equal from allensdk.core.lazy_property import LazyProperty +from allensdk.brain_observatory.behavior.data_objects import DataObject + logger = logging.getLogger(__name__) @@ -174,10 +176,10 @@ def sessions_are_equal(A, B, reraise=False) -> bool: field_set = set() for key, val in A.__dict__.items(): - if isinstance(val, LazyProperty): + if isinstance(val, LazyProperty) or isinstance(val, DataObject): field_set.add(key) for key, val in B.__dict__.items(): - if isinstance(val, LazyProperty): + if isinstance(val, LazyProperty) or isinstance(val, DataObject): field_set.add(key) logger.info(f"Comparing the following fields: {field_set}") @@ -188,6 +190,10 @@ def sessions_are_equal(A, B, reraise=False) -> bool: x1, x2 = getattr(A, field), getattr(B, field) err_msg = (f"{field} on {A} did not equal {field} " f"on {B} (\n{x1} vs\n{x2}\n)") + if isinstance(x1, DataObject): + x1 = x1.value + if isinstance(x2, DataObject): + x2 = x2.value compare_session_fields(x1, x2, err_msg) except NotImplementedError: From af7b3c05a52d6717b6441de08d04e848e972933d Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Wed, 28 Apr 2021 09:41:55 -0700 Subject: [PATCH 012/234] Add default values for cache key function params The cachetools @cached decorator `key` functionality is not quite smart enough to auto-fill default parameter values for the `hashkey` function that gets called. This commit adds those default values so missing expected parameter errors don't get raised. --- .../data_objects/running_speed/running_acquisition.py | 3 ++- .../behavior/data_objects/running_speed/running_speed.py | 9 ++++++--- .../stimulus_timestamps/stimulus_timestamps.py | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py index acd8e9a61..56ff5a6a1 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py @@ -29,7 +29,8 @@ def from_json_cache_key( def from_lims_cache_key( - cls, db, behavior_session_id: int, ophys_experiment_id: Optional[int] + cls, db, + behavior_session_id: int, ophys_experiment_id: Optional[int] = None ): return hashkey( behavior_session_id, ophys_experiment_id diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py index 7b492b9d2..3dbc7058f 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py @@ -24,14 +24,17 @@ def from_json_cache_key( - cls, dict_repr: dict, filtered: bool, zscore_threshold: float + cls, dict_repr: dict, + filtered: bool = True, + zscore_threshold: float = 10.0 ): return hashkey(json.dumps(dict_repr), filtered, zscore_threshold) def from_lims_cache_key( - cls, db, behavior_session_id: int, ophys_experiment_id: Optional[int], - filtered: bool, zscore_threshold: float + cls, db, + behavior_session_id: int, ophys_experiment_id: Optional[int] = None, + filtered: bool = True, zscore_threshold: float = 10.0 ): return hashkey( behavior_session_id, ophys_experiment_id, filtered, zscore_threshold diff --git a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py index 7aac1fbb4..539e8973c 100644 --- a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py +++ b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py @@ -24,7 +24,8 @@ def from_json_cache_key(cls, dict_repr: dict): def from_lims_cache_key( - cls, db, behavior_session_id: int, ophys_experiment_id: int + cls, db, behavior_session_id: int, + ophys_experiment_id: Optional[int] = None ): return hashkey(behavior_session_id, ophys_experiment_id) From 56fc59b0d86c5753045e56cc51d899c75e0edf1a Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Wed, 28 Apr 2021 13:45:09 -0700 Subject: [PATCH 013/234] Fix bug when comparing BehaviorSession from JSON vs NWB The BehaviorMetadata class ands up determining `indicator` (e.g. 'GCaMP') for both BehaviorSession and OphysExperiments. Unfortunately, the "indicator" field does not get saved to NWB for BehaviorSession's and gets saved to an NWB ImagingPlane object for OphysExperiments. Luckily, "indicator" can be determined from the "reporter_line" field (which exists for both BehaviorSessions and OphysExperiments). This commit adds the "indicator" field to the metadata dict when loading BehaviorSession metadata from a behavior NWB. --- .../behavior/session_apis/data_io/behavior_nwb_api.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py index 364e5974a..59345079a 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py @@ -198,6 +198,9 @@ def get_metadata(self) -> dict: data['driver_line'] = sorted(list(nwb_subject.driver_line)) data['cre_line'] = BehaviorMetadata.parse_cre_line( full_genotype=nwb_subject.genotype) + data['indicator'] = BehaviorMetadata.parse_indicator( + reporter_line=nwb_subject.reporter_line, warn=True + ) # Add other metadata stored in nwb file to behavior session meta data['date_of_acquisition'] = self.nwbfile.session_start_time From 0c4f1608d5f706c8efac27ba13583251f7d807eb Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Wed, 28 Apr 2021 14:58:45 -0700 Subject: [PATCH 014/234] Add docs for DataObjects and DataFiles --- .../behavior/data_files/_data_file_abc.py | 39 +++++++++++++ .../behavior/data_files/stimulus_file.py | 7 +++ .../behavior/data_files/sync_file.py | 6 ++ .../behavior/data_objects/_data_object_abc.py | 56 ++++++++++++++++++- .../running_speed/running_acquisition.py | 31 +++++++++- .../running_speed/running_speed.py | 10 ++++ .../stimulus_timestamps.py | 8 +++ 7 files changed, 153 insertions(+), 4 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_files/_data_file_abc.py b/allensdk/brain_observatory/behavior/data_files/_data_file_abc.py index 28ca9677a..37c2adbc7 100644 --- a/allensdk/brain_observatory/behavior/data_files/_data_file_abc.py +++ b/allensdk/brain_observatory/behavior/data_files/_data_file_abc.py @@ -29,6 +29,14 @@ def filepath(self) -> str: # pragma: no cover @classmethod @abc.abstractmethod def from_json(cls) -> "DataFile": # pragma: no cover + """Populates a DataFile from an input *.json likely parsed by + argschema + + Returns + ------- + DataFile: + An instantiated DataFile which has `data` and `filepath` properties + """ # Example: # filepath = dict_repr["my_data_file_path"] # return cls.instantiate(filepath=filepath) @@ -36,11 +44,27 @@ def from_json(cls) -> "DataFile": # pragma: no cover @abc.abstractmethod def to_json(self) -> dict: # pragma: no cover + """Given an already populated DataFile, return the dict that + when used with the `from_json()` classmethod would produce the same + DataFile + + Returns + ------- + dict: + The JSON (in dict form) that would produce the DataFile. + """ raise NotImplementedError() @classmethod @abc.abstractmethod def from_lims(cls) -> "DataFile": # pragma: no cover + """Populate a DataFile from an internal database (likely LIMS) + + Returns + ------- + DataFile: + An instantiated DataFile which has `data` and `filepath` properties + """ # Example: # query = """SELECT my_file FROM some_lims_table""" # filepath = dbconn.fetchone(query, strict=True) @@ -50,4 +74,19 @@ def from_lims(cls) -> "DataFile": # pragma: no cover @staticmethod @abc.abstractmethod def load_data(filepath: Union[str, Path]) -> Any: # pragma: no cover + """Given a filepath (that is meant to by read by the DataFile type), + load the contents of the file into a Python type. + (dict, DataFrame, list, etc...) + + Parameters + ---------- + filepath : Union[str, Path] + The filepath that the DataFile class should load. + + Returns + ------- + Any + A Python data type that has been parsed/loaded from the provided + filepath. + """ raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_files/stimulus_file.py b/allensdk/brain_observatory/behavior/data_files/stimulus_file.py index 2a7ae7763..bbe3faf37 100644 --- a/allensdk/brain_observatory/behavior/data_files/stimulus_file.py +++ b/allensdk/brain_observatory/behavior/data_files/stimulus_file.py @@ -21,6 +21,13 @@ def from_lims_cache_key(cls, db, behavior_session_id: int): class StimulusFile(DataFile): + """A DataFile which contains methods for accessing and loading visual + behavior stimulus *.pkl files. + + This file type contains a number of parameters collected during a behavior + session including information about stimulus presentations, rewards, + trials, and timing for all of the above. + """ def __init__(self, filepath: Union[str, Path]): super().__init__(filepath=filepath) diff --git a/allensdk/brain_observatory/behavior/data_files/sync_file.py b/allensdk/brain_observatory/behavior/data_files/sync_file.py index 4e2b73d76..45f275bb2 100644 --- a/allensdk/brain_observatory/behavior/data_files/sync_file.py +++ b/allensdk/brain_observatory/behavior/data_files/sync_file.py @@ -20,6 +20,12 @@ def from_lims_cache_key(cls, db, ophys_experiment_id: int): class SyncFile(DataFile): + """A DataFile which contains methods for accessing and loading visual + behavior stimulus *.pkl files. + + This file type contains global timing information for different data + streams collected during a behavior + ophys session. + """ def __init__(self, filepath: Union[str, Path]): super().__init__(filepath=filepath) diff --git a/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py index 4a61a2834..457944134 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py @@ -27,11 +27,39 @@ def value(self) -> Any: @classmethod @abc.abstractmethod def from_json(cls) -> "DataObject": # pragma: no cover + """Populates a DataObject from an input *.json likely parsed by + argschema + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + raise NotImplementedError() + + @abc.abstractmethod + def to_json(self) -> dict: # pragma: no cover + """Given an already populated DataObject, return the dict that + when used with the `from_json()` classmethod would produce the same + DataObject + + Returns + ------- + dict: + The JSON (in dict form) that would produce the DataObject. + """ raise NotImplementedError() @classmethod @abc.abstractmethod def from_lims(cls) -> "DataObject": # pragma: no cover + """Populate a DataObject from an internal database (likely LIMS) + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ # Example: # return cls(name="my_data_object", value=42) raise NotImplementedError() @@ -39,12 +67,34 @@ def from_lims(cls) -> "DataObject": # pragma: no cover @classmethod @abc.abstractmethod def from_nwb(cls, nwbfile: NWBFile) -> "DataObject": # pragma: no cover - raise NotImplementedError() + """Populate a DataObject from a pyNWB file object. - @abc.abstractmethod - def to_json(self) -> dict: # pragma: no cover + Parameters + ---------- + nwbfile: + The file object (NWBFile) of a pynwb dataset file. + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ raise NotImplementedError() @abc.abstractmethod def to_nwb(self, nwbfile: NWBFile) -> NWBFile: # pragma: no cover + """Given an already populated DataObject, return an pyNWB file object + that had had DataObject data added. + + Parameters + ---------- + nwbfile : NWBFile + An NWB file object + + Returns + ------- + NWBFile + An NWB file object that has had data from the DataObject added + to it. + """ raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py index 56ff5a6a1..6c4905075 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py @@ -38,13 +38,29 @@ def from_lims_cache_key( class RunningAcquisition(DataObject): + """A DataObject which contains properties and methods to load, process, + and represent running acquisition data. + + Running aquisition data is represented as: + + Pandas Dataframe with an index of timestamps and the following columns: + "dx": Angular change, computed during data collection + "v_sig": Voltage signal from the encoder + "v_in": The theoretical maximum voltage that the encoder + will reach prior to "wrapping". This should + theoretically be 5V (after crossing 5V goes to 0V, or + vice versa). In practice the encoder does not always + reach this value before wrapping, which can cause + transient spikes in speed at the voltage "wraps". + """ + def __init__( self, running_acquisition: pd.DataFrame, stimulus_file: Optional[StimulusFile] = None, stimulus_timestamps: Optional[StimulusTimestamps] = None, ): - super().__init__(name='running_acquisition', value=running_acquisition) + super().__init__(name="running_acquisition", value=running_acquisition) self._stimulus_file = stimulus_file self._stimulus_timestamps = stimulus_timestamps @@ -68,6 +84,18 @@ def from_json( ) def to_json(self) -> dict: + """[summary] + + Returns + ------- + dict + [description] + + Raises + ------ + RuntimeError + [description] + """ if self._stimulus_file is None or self._stimulus_timestamps is None: raise RuntimeError( "RunningAcquisition DataObject lacks information about the " @@ -87,6 +115,7 @@ def from_lims( behavior_session_id: int, ophys_experiment_id: Optional[int] = None, ) -> "RunningAcquisition": + stimulus_file = StimulusFile.from_lims(db, behavior_session_id) stimulus_timestamps = StimulusTimestamps.from_lims( db, behavior_session_id, ophys_experiment_id diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py index 3dbc7058f..652a170bf 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py @@ -42,6 +42,16 @@ def from_lims_cache_key( class RunningSpeed(DataObject): + """A DataObject which contains properties and methods to load, process, + and represent running speed data. + + Running speed data is represented as: + + Pandas Dataframe with the following columns: + "timestamps": Timestamps (in s) for calculated speed values + "speed": Computed running speed in cm/s + """ + def __init__( self, running_speed: pd.DataFrame, diff --git a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py index 539e8973c..ab77f086e 100644 --- a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py +++ b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py @@ -31,6 +31,14 @@ def from_lims_cache_key( class StimulusTimestamps(DataObject): + """A DataObject which contains properties and methods to load, process, + and represent visual behavior stimulus timestamp data. + + Stimulus timestamp data is represented as: + + Numpy array whose length is equal to the number of timestamps collected + and whose values are timestamps (in seconds) + """ def __init__( self, From 7eb83489d7bf004dfb2008f9ada0e4a90e4f13dc Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Thu, 29 Apr 2021 12:17:10 -0700 Subject: [PATCH 015/234] Store DataFile queries as global variables This will simplify tests. --- .../behavior/data_files/stimulus_file.py | 34 +++++++++++-------- .../behavior/data_files/sync_file.py | 30 +++++++++------- .../behavior/data_files/test_stimulus_file.py | 21 ++++-------- .../behavior/data_files/test_sync_file.py | 19 ++++------- 4 files changed, 48 insertions(+), 56 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_files/stimulus_file.py b/allensdk/brain_observatory/behavior/data_files/stimulus_file.py index bbe3faf37..04dd69323 100644 --- a/allensdk/brain_observatory/behavior/data_files/stimulus_file.py +++ b/allensdk/brain_observatory/behavior/data_files/stimulus_file.py @@ -12,6 +12,22 @@ from allensdk.brain_observatory.behavior.data_files import DataFile +# Query returns path to StimulusPickle file for given behavior session +STIMULUS_FILE_QUERY_TEMPLATE = """ + SELECT + wkf.storage_directory || wkf.filename AS stim_file + FROM + well_known_files wkf + WHERE + wkf.attachable_id = {behavior_session_id} + AND wkf.attachable_type = 'BehaviorSession' + AND wkf.well_known_file_type_id IN ( + SELECT id + FROM well_known_file_types + WHERE name = 'StimulusPickle'); +""" + + def from_json_cache_key(cls, dict_repr: dict): return hashkey(json.dumps(dict_repr)) @@ -47,21 +63,9 @@ def from_lims( cls, db: PostgresQueryMixin, behavior_session_id: Union[int, str] ) -> "StimulusFile": - # Query returns the path to the StimulusPickle file for the given - # behavior session - query = f""" - SELECT - wkf.storage_directory || wkf.filename AS stim_file - FROM - well_known_files wkf - WHERE - wkf.attachable_id = {behavior_session_id} - AND wkf.attachable_type = 'BehaviorSession' - AND wkf.well_known_file_type_id IN ( - SELECT id - FROM well_known_file_types - WHERE name = 'StimulusPickle'); - """ + query = STIMULUS_FILE_QUERY_TEMPLATE.format( + behavior_session_id=behavior_session_id + ) filepath = db.fetchone(query, strict=True) return cls(filepath=filepath) diff --git a/allensdk/brain_observatory/behavior/data_files/sync_file.py b/allensdk/brain_observatory/behavior/data_files/sync_file.py index 45f275bb2..dab04f9f7 100644 --- a/allensdk/brain_observatory/behavior/data_files/sync_file.py +++ b/allensdk/brain_observatory/behavior/data_files/sync_file.py @@ -11,6 +11,20 @@ from allensdk.brain_observatory.behavior.data_files import DataFile +# Query returns path to sync timing file associated with ophys experiment +SYNC_FILE_QUERY_TEMPLATE = """ + SELECT wkf.storage_directory || wkf.filename AS sync_file + FROM ophys_experiments oe + JOIN ophys_sessions os ON oe.ophys_session_id = os.id + JOIN well_known_files wkf ON wkf.attachable_id = os.id + JOIN well_known_file_types wkft + ON wkft.id = wkf.well_known_file_type_id + WHERE wkf.attachable_type = 'OphysSession' + AND wkft.name = 'OphysRigSync' + AND oe.id = {ophys_experiment_id}; +""" + + def from_json_cache_key(cls, dict_repr: dict): return hashkey(json.dumps(dict_repr)) @@ -45,19 +59,9 @@ def from_lims( cls, db: PostgresQueryMixin, ophys_experiment_id: Union[int, str] ) -> "SyncFile": - # Query returns the path to the sync timing file associated with the - # ophys experiment - query = f""" - SELECT wkf.storage_directory || wkf.filename AS sync_file - FROM ophys_experiments oe - JOIN ophys_sessions os ON oe.ophys_session_id = os.id - JOIN well_known_files wkf ON wkf.attachable_id = os.id - JOIN well_known_file_types wkft - ON wkft.id = wkf.well_known_file_type_id - WHERE wkf.attachable_type = 'OphysSession' - AND wkft.name = 'OphysRigSync' - AND oe.id = {ophys_experiment_id}; - """ + query = SYNC_FILE_QUERY_TEMPLATE.format( + ophys_experiment_id=ophys_experiment_id + ) filepath = db.fetchone(query, strict=True) return cls(filepath=filepath) diff --git a/allensdk/test/brain_observatory/behavior/data_files/test_stimulus_file.py b/allensdk/test/brain_observatory/behavior/data_files/test_stimulus_file.py index 2ad42f8b7..7fded55c6 100644 --- a/allensdk/test/brain_observatory/behavior/data_files/test_stimulus_file.py +++ b/allensdk/test/brain_observatory/behavior/data_files/test_stimulus_file.py @@ -7,6 +7,9 @@ from allensdk.internal.api import PostgresQueryMixin from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_files.stimulus_file import ( + STIMULUS_FILE_QUERY_TEMPLATE +) @pytest.fixture @@ -60,21 +63,9 @@ def test_stimulus_file_from_lims(stimulus_file_fixture, behavior_session_id): stimfile_cached = StimulusFile.from_lims(mock_db_conn, behavior_session_id) assert stimfile_cached.data == stim_pkl_data - # This query string has strict formatting requirements - # in order to pass Mock assert_called_once_with() so don't change it! - query = f""" - SELECT - wkf.storage_directory || wkf.filename AS stim_file - FROM - well_known_files wkf - WHERE - wkf.attachable_id = {behavior_session_id} - AND wkf.attachable_type = 'BehaviorSession' - AND wkf.well_known_file_type_id IN ( - SELECT id - FROM well_known_file_types - WHERE name = 'StimulusPickle'); - """ + query = STIMULUS_FILE_QUERY_TEMPLATE.format( + behavior_session_id=behavior_session_id + ) mock_db_conn.fetchone.assert_called_once_with(query, strict=True) diff --git a/allensdk/test/brain_observatory/behavior/data_files/test_sync_file.py b/allensdk/test/brain_observatory/behavior/data_files/test_sync_file.py index 73ade1d89..81b5631df 100644 --- a/allensdk/test/brain_observatory/behavior/data_files/test_sync_file.py +++ b/allensdk/test/brain_observatory/behavior/data_files/test_sync_file.py @@ -8,6 +8,9 @@ from allensdk.internal.api import PostgresQueryMixin from allensdk.brain_observatory.behavior.data_files import SyncFile +from allensdk.brain_observatory.behavior.data_files.sync_file import ( + SYNC_FILE_QUERY_TEMPLATE +) @pytest.fixture @@ -84,19 +87,9 @@ def test_sync_file_from_lims( stimfile_cached = SyncFile.from_lims(mock_db_conn, ophys_experiment_id) np.allclose(stimfile_cached.data, sync_data) - # This query string has strict formatting requirements - # in order to pass Mock assert_called_once_with() so don't change it! - query = f""" - SELECT wkf.storage_directory || wkf.filename AS sync_file - FROM ophys_experiments oe - JOIN ophys_sessions os ON oe.ophys_session_id = os.id - JOIN well_known_files wkf ON wkf.attachable_id = os.id - JOIN well_known_file_types wkft - ON wkft.id = wkf.well_known_file_type_id - WHERE wkf.attachable_type = 'OphysSession' - AND wkft.name = 'OphysRigSync' - AND oe.id = {ophys_experiment_id}; - """ + query = SYNC_FILE_QUERY_TEMPLATE.format( + ophys_experiment_id=ophys_experiment_id + ) mock_db_conn.fetchone.assert_called_once_with(query, strict=True) From e444143b31dc203d16297c7194bb6525fbae55e9 Mon Sep 17 00:00:00 2001 From: Nicholas Mei Date: Thu, 29 Apr 2021 12:52:53 -0700 Subject: [PATCH 016/234] Clarify docstrings for DataObject/DataFile from_json methods --- .../brain_observatory/behavior/data_files/_data_file_abc.py | 6 +++--- .../behavior/data_objects/_data_object_abc.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_files/_data_file_abc.py b/allensdk/brain_observatory/behavior/data_files/_data_file_abc.py index 37c2adbc7..7336d8590 100644 --- a/allensdk/brain_observatory/behavior/data_files/_data_file_abc.py +++ b/allensdk/brain_observatory/behavior/data_files/_data_file_abc.py @@ -28,9 +28,9 @@ def filepath(self) -> str: # pragma: no cover @classmethod @abc.abstractmethod - def from_json(cls) -> "DataFile": # pragma: no cover - """Populates a DataFile from an input *.json likely parsed by - argschema + def from_json(cls, dict_repr: dict) -> "DataFile": # pragma: no cover + """Populates a DataFile from a JSON compatible dict (likely parsed by + argschema) Returns ------- diff --git a/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py index 457944134..619487262 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py @@ -26,9 +26,9 @@ def value(self) -> Any: @classmethod @abc.abstractmethod - def from_json(cls) -> "DataObject": # pragma: no cover - """Populates a DataObject from an input *.json likely parsed by - argschema + def from_json(cls, dict_repr: dict) -> "DataObject": # pragma: no cover + """Populates a DataFile from a JSON compatible dict (likely parsed by + argschema) Returns ------- From 065bd2bc660dd3e82182203d52c98ca5f9b0a69c Mon Sep 17 00:00:00 2001 From: aamster Date: Fri, 4 Jun 2021 07:32:07 -0700 Subject: [PATCH 017/234] Initial from_internal for behavior metadata --- .../tables/sessions_table.py | 3 +- .../behavior/behavior_session.py | 44 +- .../behavior/data_files/stimulus_file.py | 3 +- .../behavior/data_objects/__init__.py | 5 +- .../behavior/data_objects/_base/__init__.py | 0 .../{ => _base}/_data_object_abc.py | 27 - .../_base/readable_mixins/__init__.py | 0 .../internal_mixed_readable_mixin.py | 21 + .../readable_mixins/json_readable_mixin.py | 19 + .../readable_mixins/lims_readable_mixin.py | 20 + .../stimulus_file_readable_mixin.py | 19 + .../sync_file_readable_mixin.py | 19 + .../data_objects/metadata/__init__.py | 0 .../metadata/behavior_metadata/__init__.py | 0 .../metadata/behavior_metadata/age.py | 72 + .../behavior_metadata}/behavior_metadata.py | 386 ++--- .../behavior_metadata}/behavior_session_id.py | 5 +- .../behavior_session_uuid.py | 55 + .../behavior_metadata/date_of_acquisition.py | 80 + .../metadata/behavior_metadata/driver_line.py | 51 + .../behavior_metadata/equipment_name.py | 36 + .../metadata/behavior_metadata/foraging_id.py | 44 + .../behavior_metadata/full_genotype.py | 66 + .../metadata/behavior_metadata/mouse_id.py | 45 + .../behavior_metadata/reporter_line.py | 117 ++ .../behavior_metadata/session_type.py | 49 + .../metadata/behavior_metadata/sex.py | 40 + .../behavior_metadata/stimulus_frame_rate.py | 31 + .../ophys_experiment_metadata/__init__.py | 0 .../running_speed/running_acquisition.py | 4 +- .../running_speed/running_speed.py | 4 +- .../stimulus_timestamps.py | 73 +- .../metadata/behavior_ophys_metadata.py | 3 +- .../abcs/session_base/behavior_base.py | 3 +- .../session_apis/data_io/behavior_nwb_api.py | 3 +- .../data_io/behavior_ophys_nwb_api.py | 3 +- .../behavior_data_transforms.py | 3 +- .../behavior/swdb/behavior_project_cache.py | 3 +- .../test-reports/test.xml | 1 + .../behavior/test-reports/test.xml | 1294 +++++++++++++++++ .../behavior/test_behavior_lims_api.py | 3 +- .../behavior/test_behavior_metadata.py | 3 +- .../test_behavior_ophys_data_xforms.py | 3 +- 43 files changed, 2332 insertions(+), 328 deletions(-) create mode 100644 allensdk/brain_observatory/behavior/data_objects/_base/__init__.py rename allensdk/brain_observatory/behavior/data_objects/{ => _base}/_data_object_abc.py (71%) create mode 100644 allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/__init__.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/internal_mixed_readable_mixin.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/json_readable_mixin.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/lims_readable_mixin.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/stimulus_file_readable_mixin.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/sync_file_readable_mixin.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/__init__.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/__init__.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py rename allensdk/brain_observatory/behavior/{metadata => data_objects/metadata/behavior_metadata}/behavior_metadata.py (58%) rename allensdk/brain_observatory/behavior/data_objects/{ => metadata/behavior_metadata}/behavior_session_id.py (90%) create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/driver_line.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/full_genotype.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/mouse_id.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/reporter_line.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/sex.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/__init__.py create mode 100644 allensdk/test/brain_observatory/behavior/behavior_project_cache/test-reports/test.xml create mode 100644 allensdk/test/brain_observatory/behavior/test-reports/test.xml diff --git a/allensdk/brain_observatory/behavior/behavior_project_cache/tables/sessions_table.py b/allensdk/brain_observatory/behavior/behavior_project_cache/tables/sessions_table.py index eaeedfed7..ed4d8b026 100644 --- a/allensdk/brain_observatory/behavior/behavior_project_cache/tables/sessions_table.py +++ b/allensdk/brain_observatory/behavior/behavior_project_cache/tables/sessions_table.py @@ -13,7 +13,8 @@ from allensdk.brain_observatory.behavior.behavior_project_cache.tables \ .project_table import \ ProjectTable -from allensdk.brain_observatory.behavior.metadata.behavior_metadata import \ +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ BehaviorMetadata from allensdk.brain_observatory.behavior.behavior_project_cache.project_apis.data_io import BehaviorProjectLimsApi # noqa: E501 diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index a278e2ffc..37a0ef674 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -5,7 +5,14 @@ import numpy as np import inspect -from allensdk.brain_observatory.behavior.metadata.behavior_metadata import \ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .internal_mixed_readable_mixin import \ + InternalMixedReadableMixin +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ BehaviorMetadata from allensdk.core.lazy_property import LazyPropertyMixin from allensdk.brain_observatory.session_api_utils import ParamsMixin @@ -16,7 +23,8 @@ from allensdk.brain_observatory.behavior.trials_processing import ( construct_rolling_performance_df, calculate_reward_rate_fix_nans) from allensdk.brain_observatory.behavior.data_objects import ( - BehaviorSessionId, StimulusTimestamps, RunningSpeed, RunningAcquisition + BehaviorSessionId, StimulusTimestamps, RunningSpeed, RunningAcquisition, + DataObject ) from allensdk.core.auth_config import LIMS_DB_CREDENTIAL_MAP @@ -26,7 +34,8 @@ BehaviorDataApi = Type[BehaviorBase] -class BehaviorSession(LazyPropertyMixin): +class BehaviorSession(DataObject, InternalMixedReadableMixin, + LazyPropertyMixin): def __init__( self, api: Optional[BehaviorDataApi] = None, behavior_session_id: BehaviorSessionId = None, @@ -34,7 +43,9 @@ def __init__( running_acquisition: RunningAcquisition = None, raw_running_speed: RunningSpeed = None, running_speed: RunningSpeed = None, + metadata: BehaviorMetadata = None ): + super().__init__(name='behavior_session', value=self) self.api = api # LazyProperty constructor provided by LazyPropertyMixin @@ -56,7 +67,7 @@ def __init__( self._task_parameters = LazyProperty(self.api.get_task_parameters, settable=True) self._trials = LazyProperty(self.api.get_trials, settable=True) - self._metadata = LazyProperty(self.api.get_metadata, settable=True) + self._metadata = metadata # ==================== class and utility methods ====================== @@ -79,14 +90,17 @@ def from_json(cls, session_data: dict) -> "BehaviorSession": ) @classmethod - def from_lims(cls, behavior_session_id: int) -> "BehaviorSession": + def from_internal_mixed(cls, + behavior_session_id: int) -> "BehaviorSession": lims_db = db_connection_creator( fallback_credentials=LIMS_DB_CREDENTIAL_MAP ) behavior_session_id = BehaviorSessionId(behavior_session_id) - stimulus_timestamps = StimulusTimestamps.from_lims( - lims_db, behavior_session_id.value + stimulus_file = StimulusFile.from_lims( + db=lims_db, behavior_session_id=behavior_session_id.value) + stimulus_timestamps = StimulusTimestamps.from_stimulus_file( + stimulus_file=stimulus_file ) running_acquisition = RunningAcquisition.from_lims( lims_db, behavior_session_id.value @@ -97,17 +111,23 @@ def from_lims(cls, behavior_session_id: int) -> "BehaviorSession": running_speed = RunningSpeed.from_lims( lims_db, behavior_session_id.value ) + behavior_metadata = BehaviorMetadata.from_internal_mixed( + behavior_session_id=behavior_session_id, lims_db=lims_db, + stimulus_file=stimulus_file, + stimulus_timestamps=stimulus_timestamps + ) return cls( api=BehaviorLimsApi(behavior_session_id.value), behavior_session_id=behavior_session_id, stimulus_timestamps=stimulus_timestamps, running_acquisition=running_acquisition, raw_running_speed=raw_running_speed, - running_speed=running_speed + running_speed=running_speed, + metadata=behavior_metadata ) @classmethod - def from_nwb_path( + def from_nwb( cls, nwb_path: str, **api_kwargs: Any ) -> "BehaviorSession": with pynwb.NWBHDF5IO(str(nwb_path), 'r') as read_io: @@ -126,6 +146,12 @@ def from_nwb_path( running_speed=running_speed ) + def to_json(self) -> dict: + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass + def cache_clear(self) -> None: """Convenience method to clear the api cache, if applicable.""" try: diff --git a/allensdk/brain_observatory/behavior/data_files/stimulus_file.py b/allensdk/brain_observatory/behavior/data_files/stimulus_file.py index 04dd69323..062db67f9 100644 --- a/allensdk/brain_observatory/behavior/data_files/stimulus_file.py +++ b/allensdk/brain_observatory/behavior/data_files/stimulus_file.py @@ -1,5 +1,5 @@ import json -from typing import Dict, Union +from typing import Dict, Union, Optional from pathlib import Path from cachetools import cached, LRUCache @@ -11,7 +11,6 @@ from allensdk.internal.core.lims_utilities import safe_system_path from allensdk.brain_observatory.behavior.data_files import DataFile - # Query returns path to StimulusPickle file for given behavior session STIMULUS_FILE_QUERY_TEMPLATE = """ SELECT diff --git a/allensdk/brain_observatory/behavior/data_objects/__init__.py b/allensdk/brain_observatory/behavior/data_objects/__init__.py index 7ae413984..088722aec 100644 --- a/allensdk/brain_observatory/behavior/data_objects/__init__.py +++ b/allensdk/brain_observatory/behavior/data_objects/__init__.py @@ -1,5 +1,6 @@ -from allensdk.brain_observatory.behavior.data_objects._data_object_abc import DataObject # noqa: E501, F401 -from allensdk.brain_observatory.behavior.data_objects.behavior_session_id import BehaviorSessionId # noqa: E501, F401 +from allensdk.brain_observatory.behavior.data_objects._base._data_object_abc import DataObject # noqa: E501, F401 +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_session_id import BehaviorSessionId # noqa: E501, F401 from allensdk.brain_observatory.behavior.data_objects.stimulus_timestamps.stimulus_timestamps import StimulusTimestamps # noqa: E501, F401 from allensdk.brain_observatory.behavior.data_objects.running_speed.running_speed import RunningSpeed # noqa: E501, F401 from allensdk.brain_observatory.behavior.data_objects.running_speed.running_acquisition import RunningAcquisition # noqa: E501, F401 diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/__init__.py b/allensdk/brain_observatory/behavior/data_objects/_base/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py similarity index 71% rename from allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py rename to allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py index 619487262..0a9065994 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py @@ -24,19 +24,6 @@ def name(self) -> str: def value(self) -> Any: return self._value - @classmethod - @abc.abstractmethod - def from_json(cls, dict_repr: dict) -> "DataObject": # pragma: no cover - """Populates a DataFile from a JSON compatible dict (likely parsed by - argschema) - - Returns - ------- - DataObject: - An instantiated DataObject which has `name` and `value` properties - """ - raise NotImplementedError() - @abc.abstractmethod def to_json(self) -> dict: # pragma: no cover """Given an already populated DataObject, return the dict that @@ -50,20 +37,6 @@ def to_json(self) -> dict: # pragma: no cover """ raise NotImplementedError() - @classmethod - @abc.abstractmethod - def from_lims(cls) -> "DataObject": # pragma: no cover - """Populate a DataObject from an internal database (likely LIMS) - - Returns - ------- - DataObject: - An instantiated DataObject which has `name` and `value` properties - """ - # Example: - # return cls(name="my_data_object", value=42) - raise NotImplementedError() - @classmethod @abc.abstractmethod def from_nwb(cls, nwbfile: NWBFile) -> "DataObject": # pragma: no cover diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/__init__.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/internal_mixed_readable_mixin.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/internal_mixed_readable_mixin.py new file mode 100644 index 000000000..a50d3e15c --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/internal_mixed_readable_mixin.py @@ -0,0 +1,21 @@ +import abc + +from allensdk.brain_observatory.behavior.data_objects import DataObject + + +class InternalMixedReadableMixin: + """Marks a data object as readable from a variety of internal data sources + """ + @classmethod + @abc.abstractmethod + def from_internal_mixed(cls, *args) -> "DataObject": # pragma: no cover + """Populate a DataObject from various internal data sources + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + # Example: + # return cls(name="my_data_object", value=42) + raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/json_readable_mixin.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/json_readable_mixin.py new file mode 100644 index 000000000..5bc8fe3e6 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/json_readable_mixin.py @@ -0,0 +1,19 @@ +import abc + +from allensdk.brain_observatory.behavior.data_objects import DataObject + + +class JsonReadableMixin: + """Marks a data object as readable from json""" + @classmethod + @abc.abstractmethod + def from_json(cls, dict_repr: dict) -> "DataObject": # pragma: no cover + """Populates a DataFile from a JSON compatible dict (likely parsed by + argschema) + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/lims_readable_mixin.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/lims_readable_mixin.py new file mode 100644 index 000000000..8f77aca48 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/lims_readable_mixin.py @@ -0,0 +1,20 @@ +import abc + +from allensdk.brain_observatory.behavior.data_objects import DataObject + + +class LimsReadableMixin: + """Marks a data object as readable from LIMS""" + @classmethod + @abc.abstractmethod + def from_lims(cls, *args) -> "DataObject": # pragma: no cover + """Populate a DataObject from an internal database (likely LIMS) + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + # Example: + # return cls(name="my_data_object", value=42) + raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/stimulus_file_readable_mixin.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/stimulus_file_readable_mixin.py new file mode 100644 index 000000000..0645bb62a --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/stimulus_file_readable_mixin.py @@ -0,0 +1,19 @@ +import abc + +from allensdk.brain_observatory.behavior.data_objects import DataObject + + +class StimulusFileReadableMixin: + """Marks a data object as readable from stimulus file""" + @classmethod + @abc.abstractmethod + def from_stimulus_file(cls, *args) \ + -> "DataObject": # pragma: no cover + """Populate a DataObject from the stimulus file + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/sync_file_readable_mixin.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/sync_file_readable_mixin.py new file mode 100644 index 000000000..bbcb7850b --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/sync_file_readable_mixin.py @@ -0,0 +1,19 @@ +import abc + +from allensdk.brain_observatory.behavior.data_objects import DataObject + + +class SyncFileReadableMixin: + """Marks a data object as readable from sync file""" + @classmethod + @abc.abstractmethod + def from_sync_file(cls, *args) \ + -> "DataObject": # pragma: no cover + """Populate a DataObject from the sync file + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/__init__.py b/allensdk/brain_observatory/behavior/data_objects/metadata/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/__init__.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py new file mode 100644 index 000000000..bc8273513 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py @@ -0,0 +1,72 @@ +import re +import warnings +from typing import Optional + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.internal.api import PostgresQueryMixin + + +class Age(DataObject): + """Age of animal (in days)""" + def __init__(self, age: int): + super().__init__(name="age_in_days", value=age) + + @classmethod + def from_json(cls, dict_repr: dict) -> "Age": + age = dict_repr["age"] + age = cls._age_code_to_days(age=age) + return cls(age=age) + + def to_json(self) -> dict: + return {"sex": self.value} + + @classmethod + def from_lims(cls, behavior_session_id: int, + lims_db: PostgresQueryMixin) -> "Age": + query = f""" + SELECT a.name AS age + FROM behavior_sessions bs + JOIN donors d ON d.id = bs.donor_id + JOIN ages a ON a.id = d.age_id + WHERE bs.id = {behavior_session_id}; + """ + age = lims_db.fetchone(query, strict=True) + age = cls._age_code_to_days(age=age) + return cls(age=age) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "EquipmentName": + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass + + @staticmethod + def _age_code_to_days(age: str, warn=False) -> Optional[int]: + """Converts the age code into a numeric days representation + + Parameters + ---------- + age + age code, ie P123 + warn + Whether to output warning if parsing fails + """ + if not age.startswith('P'): + if warn: + warnings.warn('Could not parse numeric age from age code ' + '(age code does not start with "P")') + return None + + match = re.search(r'\d+', age) + + if match is None: + if warn: + warnings.warn('Could not parse numeric age from age code ' + '(no numeric values found in age code)') + return None + + start, end = match.span() + return int(age[start:end]) diff --git a/allensdk/brain_observatory/behavior/metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py similarity index 58% rename from allensdk/brain_observatory/behavior/metadata/behavior_metadata.py rename to allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index a057e01db..d5c63c622 100644 --- a/allensdk/brain_observatory/behavior/metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -1,16 +1,56 @@ import abc import uuid -import warnings from datetime import datetime from typing import Dict, List, Optional import re import numpy as np -import pytz - -from allensdk.brain_observatory.behavior.session_apis.abcs.\ - data_extractor_base.behavior_data_extractor_base import \ - BehaviorDataExtractorBase +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects import DataObject, \ + StimulusTimestamps, BehaviorSessionId +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .internal_mixed_readable_mixin \ + import \ + InternalMixedReadableMixin +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.age import \ + Age +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_session_uuid import \ + BehaviorSessionUUID +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.date_of_acquisition import \ + DateOfAcquisition +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.driver_line import \ + DriverLine +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.equipment_name import \ + EquipmentName +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.foraging_id import \ + ForagingId +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.full_genotype import \ + FullGenotype +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.mouse_id import \ + MouseId +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.reporter_line import \ + ReporterLine +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.session_type import \ + SessionType +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.sex import \ + Sex +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.stimulus_frame_rate import \ + StimulusFrameRate from allensdk.brain_observatory.session_api_utils import compare_session_fields +from allensdk.internal.api import PostgresQueryMixin description_dict = { # key is a regex and value is returned on match @@ -151,250 +191,166 @@ def get_task_parameters(data: Dict) -> Dict: return task_parameters -class BehaviorMetadata: +class BehaviorMetadata(DataObject, InternalMixedReadableMixin): """Container class for behavior metadata""" - def __init__(self, extractor: BehaviorDataExtractorBase, - stimulus_timestamps: np.ndarray, - behavior_stimulus_file: dict): + def __init__(self, + behavior_session_id: BehaviorSessionId, + equipment_name: EquipmentName, + sex: Sex, + age: Age, + stimulus_frame_rate: StimulusFrameRate, + session_type: SessionType, + date_of_acquisition: DateOfAcquisition, + reporter_line: ReporterLine, + full_genotype: FullGenotype, + behavior_session_uuid: BehaviorSessionUUID, + driver_line: DriverLine, + mouse_id: MouseId): + super().__init__(name='behavior_metadata', value=self) + self._behavior_session_id = behavior_session_id + self._equipment_name = equipment_name + self._sex = sex + self._age = age + self._stimulus_frame_rate = stimulus_frame_rate + self._session_type = session_type + self._date_of_acquisition = date_of_acquisition + self._reporter_line = reporter_line + self._full_genotype = full_genotype + self._behavior_session_uuid = behavior_session_uuid + self._driver_line = driver_line + self._mouse_id = mouse_id - self._extractor = extractor - self._stimulus_timestamps = stimulus_timestamps - self._behavior_stimulus_file = behavior_stimulus_file self._exclude_from_equals = set() + @classmethod + def from_internal_mixed( + cls, + behavior_session_id: BehaviorSessionId, + stimulus_file: StimulusFile, + stimulus_timestamps: StimulusTimestamps, + lims_db: PostgresQueryMixin + ) -> "BehaviorMetadata": + equipment_name = EquipmentName.from_lims( + behavior_session_id=behavior_session_id.value, lims_db=lims_db) + sex = Sex.from_lims(behavior_session_id=behavior_session_id.value, + lims_db=lims_db) + age = Age.from_lims(behavior_session_id=behavior_session_id.value, + lims_db=lims_db) + stimulus_frame_rate = StimulusFrameRate.from_stimulus_file( + stimulus_timestamps=stimulus_timestamps) + session_type = SessionType.from_stimulus_file( + stimulus_file=stimulus_file) + date_of_acquisition = DateOfAcquisition.from_lims( + behavior_session_id=behavior_session_id.value, lims_db=lims_db)\ + .validate(stimulus_file=stimulus_file, + behavior_session_id=behavior_session_id.value) + reporter_line = ReporterLine.from_lims( + behavior_session_id=behavior_session_id.value, lims_db=lims_db) + full_genotype = FullGenotype.from_lims( + behavior_session_id=behavior_session_id.value, lims_db=lims_db) + + foraging_id = ForagingId.from_lims( + behavior_session_id=behavior_session_id.value, lims_db=lims_db) + behavior_session_uuid = BehaviorSessionUUID.from_stimulus_file( + stimulus_file=stimulus_file)\ + .validate(behavior_session_id=behavior_session_id.value, + foraging_id=foraging_id.value, + stimulus_file=stimulus_file) + driver_line = DriverLine.from_lims( + behavior_session_id=behavior_session_id.value, lims_db=lims_db) + mouse_id = MouseId.from_lims( + behavior_session_id=behavior_session_id.value, + lims_db=lims_db) + + return cls( + behavior_session_id=behavior_session_id, + equipment_name=equipment_name, + sex=sex, + age=age, + stimulus_frame_rate=stimulus_frame_rate, + session_type=session_type, + date_of_acquisition=date_of_acquisition, + reporter_line=reporter_line, + full_genotype=full_genotype, + behavior_session_uuid=behavior_session_uuid, + driver_line=driver_line, + mouse_id=mouse_id + ) + + @classmethod + def from_json(cls, dict_repr: dict) -> "BehaviorMetadata": + pass + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorMetadata": + pass + @property def equipment_name(self) -> str: - return self._extractor.get_equipment_name() + return self._equipment_name.value @property def sex(self) -> str: - return self._extractor.get_sex() + return self._sex.value @property def age_in_days(self) -> Optional[int]: - """Converts the age cod into a numeric days representation""" - - age = self._extractor.get_age() - return self.parse_age_in_days(age=age, warn=True) + return self._age.value @property def stimulus_frame_rate(self) -> float: - return self._get_frame_rate(timestamps=self._stimulus_timestamps) + return self._stimulus_frame_rate.value @property def session_type(self) -> str: - return self._extractor.get_stimulus_name() + return self._session_type.value @property def date_of_acquisition(self) -> datetime: - """Return the timestamp for when experiment was started in UTC - - NOTE: This method will only get acquisition datetime from - extractor (data from LIMS) methods. As a sanity check, - it will also read the acquisition datetime from the behavior stimulus - (*.pkl) file and raise a warning if the date differs too much from the - datetime obtained from the behavior stimulus (*.pkl) file. - - :rtype: datetime - """ - extractor_acq_date = self._extractor.get_date_of_acquisition() - - pkl_data = self._behavior_stimulus_file - pkl_raw_acq_date = pkl_data["start_time"] - if isinstance(pkl_raw_acq_date, datetime): - pkl_acq_date = pytz.utc.localize(pkl_raw_acq_date) - - elif isinstance(pkl_raw_acq_date, (int, float)): - # We are dealing with an older pkl file where the acq time is - # stored as a Unix style timestamp string - parsed_pkl_acq_date = datetime.fromtimestamp(pkl_raw_acq_date) - pkl_acq_date = pytz.utc.localize(parsed_pkl_acq_date) - else: - pkl_acq_date = None - warnings.warn( - "Could not parse the acquisition datetime " - f"({pkl_raw_acq_date}) found in the following stimulus *.pkl: " - f"{self._extractor.get_behavior_stimulus_file()}" - ) - - if pkl_acq_date: - acq_start_diff = ( - extractor_acq_date - pkl_acq_date).total_seconds() - # If acquisition dates differ by more than an hour - if abs(acq_start_diff) > 3600: - session_id = self._extractor.get_behavior_session_id() - warnings.warn( - "The `date_of_acquisition` field in LIMS " - f"({extractor_acq_date}) for behavior session " - f"({session_id}) deviates by more " - f"than an hour from the `start_time` ({pkl_acq_date}) " - "specified in the associated stimulus *.pkl file: " - f"{self._extractor.get_behavior_stimulus_file()}" - ) - return extractor_acq_date + return self._date_of_acquisition.value @property def reporter_line(self) -> Optional[str]: - reporter_line = self._extractor.get_reporter_line() - return self.parse_reporter_line(reporter_line=reporter_line, warn=True) + return self._reporter_line.value @property def indicator(self) -> Optional[str]: - """Parses indicator from reporter""" - reporter_line = self.reporter_line - return self.parse_indicator(reporter_line=reporter_line, warn=True) + return self._reporter_line.indicator + + @property + def full_genotype(self) -> str: + return self._full_genotype.value @property def cre_line(self) -> Optional[str]: - """Parses cre_line from full_genotype""" - cre_line = self.parse_cre_line(full_genotype=self.full_genotype, - warn=True) - return cre_line + return self._full_genotype.parse_cre_line(warn=True) @property def behavior_session_uuid(self) -> Optional[uuid.UUID]: - """Get the universally unique identifier (UUID) - """ - data = self._behavior_stimulus_file - behavior_pkl_uuid = data.get("session_uuid") - - behavior_session_id = self._extractor.get_behavior_session_id() - foraging_id = self._extractor.get_foraging_id() - - # Sanity check to ensure that pkl file data matches up with - # the behavior session that the pkl file has been associated with. - assert_err_msg = ( - f"The behavior session UUID ({behavior_pkl_uuid}) in the " - f"behavior stimulus *.pkl file " - f"({self._extractor.get_behavior_stimulus_file()}) does " - f"does not match the foraging UUID ({foraging_id}) for " - f"behavior session: {behavior_session_id}") - assert behavior_pkl_uuid == foraging_id, assert_err_msg - - if behavior_pkl_uuid is None: - bs_uuid = None - else: - bs_uuid = uuid.UUID(behavior_pkl_uuid) - return bs_uuid + return self._behavior_session_uuid.value @property def driver_line(self) -> List[str]: - return sorted(self._extractor.get_driver_line()) + return self._driver_line.value @property def mouse_id(self) -> int: - return self._extractor.get_mouse_id() - - @property - def full_genotype(self) -> str: - return self._extractor.get_full_genotype() + return self._mouse_id.value @property def behavior_session_id(self) -> int: - return self._extractor.get_behavior_session_id() + return self._behavior_session_id.value - def get_extractor(self): - return self._extractor - - @abc.abstractmethod def to_dict(self) -> dict: """Returns dict representation of all properties in class""" vars_ = vars(BehaviorMetadata) return self._get_properties(vars_=vars_) - @staticmethod - def _get_frame_rate(timestamps: np.ndarray): - return np.round(1 / np.mean(np.diff(timestamps)), 0) - - @staticmethod - def parse_cre_line(full_genotype: str, warn=False) -> Optional[str]: - """ - Parameters - ---------- - full_genotype - formatted from LIMS, e.g. - Vip-IRES-Cre/wt;Ai148(TIT2L-GC6f-ICL-tTA2)/wt - warn - Whether to output warning if parsing fails - - Returns - ---------- - cre_line - just the Cre line, e.g. Vip-IRES-Cre, or None if not possible to - parse - """ - if ';' not in full_genotype: - if warn: - warnings.warn('Unable to parse cre_line from full_genotype') - return None - return full_genotype.split(';')[0].replace('/wt', '') - - @staticmethod - def parse_age_in_days(age: str, warn=False) -> Optional[int]: - """Converts the age code into a numeric days representation - - Parameters - ---------- - age - age code, ie P123 - warn - Whether to output warning if parsing fails - """ - if not age.startswith('P'): - if warn: - warnings.warn('Could not parse numeric age from age code ' - '(age code does not start with "P")') - return None - - match = re.search(r'\d+', age) - - if match is None: - if warn: - warnings.warn('Could not parse numeric age from age code ' - '(no numeric values found in age code)') - return None - - start, end = match.span() - return int(age[start:end]) - - @staticmethod - def parse_reporter_line(reporter_line: Optional[List[str]], - warn=False) -> Optional[str]: - """There can be multiple reporter lines, so it is returned from LIMS - as a list. But there shouldn't be more than 1 for behavior. This - tries to convert to str - - Parameters - ---------- - reporter_line - List of reporter line - warn - Whether to output warnings if parsing fails - - Returns - --------- - single reporter line, or None if not possible - """ - if reporter_line is None: - if warn: - warnings.warn('Error parsing reporter line. It is null.') - return None - - if len(reporter_line) == 0: - if warn: - warnings.warn('Error parsing reporter line. ' - 'The array is empty') - return None - - if isinstance(reporter_line, str): - return reporter_line - - if len(reporter_line) > 1: - if warn: - warnings.warn('More than 1 reporter line. Returning the first ' - 'one') - - return reporter_line[0] + def to_json(self) -> dict: + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass def _get_properties(self, vars_: dict): """Returns all property names and values""" @@ -425,29 +381,3 @@ def __eq__(self, other): except AssertionError: return False return True - - @staticmethod - def parse_indicator(reporter_line: Optional[str], warn=False) -> Optional[ - str]: - """Parses indicator from reporter""" - reporter_substring_indicator_map = { - 'GCaMP6f': 'GCaMP6f', - 'GC6f': 'GCaMP6f', - 'GCaMP6s': 'GCaMP6s' - } - if reporter_line is None: - if warn: - warnings.warn( - 'Could not parse indicator from reporter because ' - 'there is no reporter') - return None - - for substr, indicator in reporter_substring_indicator_map.items(): - if substr in reporter_line: - return indicator - - if warn: - warnings.warn( - 'Could not parse indicator from reporter because none' - 'of the expected substrings were found in the reporter') - return None diff --git a/allensdk/brain_observatory/behavior/data_objects/behavior_session_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py similarity index 90% rename from allensdk/brain_observatory/behavior/data_objects/behavior_session_id.py rename to allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py index 6c9e0e1ca..513b25fdd 100644 --- a/allensdk/brain_observatory/behavior/data_objects/behavior_session_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py @@ -3,6 +3,9 @@ from cachetools import cached, LRUCache from cachetools.keys import hashkey +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .lims_readable_mixin import \ + LimsReadableMixin from allensdk.internal.api import PostgresQueryMixin from allensdk.brain_observatory.behavior.data_objects import DataObject @@ -11,7 +14,7 @@ def from_lims_cache_key(cls, db, ophys_experiment_id: int): return hashkey(ophys_experiment_id) -class BehaviorSessionId(DataObject): +class BehaviorSessionId(DataObject, LimsReadableMixin): def __init__(self, behavior_session_id: int): super().__init__(name="behavior_session_id", value=behavior_session_id) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py new file mode 100644 index 000000000..0a3a38bd3 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py @@ -0,0 +1,55 @@ +import uuid +from typing import Optional + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .stimulus_file_readable_mixin import \ + StimulusFileReadableMixin + + +class BehaviorSessionUUID(DataObject, StimulusFileReadableMixin): + """the universally unique identifier (UUID)""" + def __init__(self, behavior_session_uuid: Optional[uuid.UUID]): + super().__init__(name="behavior_session_uuid", value=behavior_session_uuid) + + @classmethod + def from_json(cls, dict_repr: dict) -> "BehaviorSessionUUID": + pass + + def to_json(self) -> dict: + return {"sex": self.value} + + @classmethod + def from_stimulus_file( + cls, stimulus_file: StimulusFile) -> "BehaviorSessionUUID": + id = stimulus_file.data.get('session_uuid') + if id: + id = uuid.UUID(id) + return cls(behavior_session_uuid=id) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorSessionUUID": + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass + + def validate(self, behavior_session_id: int, + foraging_id: int, + stimulus_file: StimulusFile) -> "BehaviorSessionUUID": + """ + Sanity check to ensure that pkl file data matches up with + the behavior session that the pkl file has been associated with. + """ + assert_err_msg = ( + f"The behavior session UUID ({self.value}) in the " + f"behavior stimulus *.pkl file " + f"({stimulus_file.filepath}) does " + f"does not match the foraging UUID ({foraging_id}) for " + f"behavior session: {behavior_session_id}") + assert self.value == foraging_id, assert_err_msg + + return self diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py new file mode 100644 index 000000000..0268124de --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py @@ -0,0 +1,80 @@ +import warnings +from datetime import datetime + +import pytz +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .lims_readable_mixin import \ + LimsReadableMixin +from allensdk.internal.api import PostgresQueryMixin + + +class DateOfAcquisition(DataObject, LimsReadableMixin): + """timestamp for when experiment was started in UTC""" + def __init__(self, date_of_acquisition: float): + super().__init__(name="date_of_acquisition", value=date_of_acquisition) + + def to_json(self) -> dict: + return {"stimulus_frame_rate": self.value} + + @classmethod + def from_lims( + cls, behavior_session_id: int, + lims_db: PostgresQueryMixin) -> "DateOfAcquisition": + query = """ + SELECT bs.date_of_acquisition + FROM behavior_sessions bs + WHERE bs.id = {}; + """.format(behavior_session_id) + + experiment_date = lims_db.fetchone(query, strict=True) + experiment_date = pytz.utc.localize(experiment_date) + return cls(date_of_acquisition=experiment_date) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "DateOfAcquisition": + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass + + def validate(self, stimulus_file: StimulusFile, + behavior_session_id: int) -> "DateOfAcquisition": + """raise a warning if the date differs too much from the + datetime obtained from the behavior stimulus (*.pkl) file.""" + pkl_data = stimulus_file.data + pkl_raw_acq_date = pkl_data["start_time"] + if isinstance(pkl_raw_acq_date, datetime): + pkl_acq_date = pytz.utc.localize(pkl_raw_acq_date) + + elif isinstance(pkl_raw_acq_date, (int, float)): + # We are dealing with an older pkl file where the acq time is + # stored as a Unix style timestamp string + parsed_pkl_acq_date = datetime.fromtimestamp(pkl_raw_acq_date) + pkl_acq_date = pytz.utc.localize(parsed_pkl_acq_date) + else: + pkl_acq_date = None + warnings.warn( + "Could not parse the acquisition datetime " + f"({pkl_raw_acq_date}) found in the following stimulus *.pkl: " + f"{stimulus_file.filepath}" + ) + + if pkl_acq_date: + acq_start_diff = ( + self.value - pkl_acq_date).total_seconds() + # If acquisition dates differ by more than an hour + if abs(acq_start_diff) > 3600: + session_id = behavior_session_id + warnings.warn( + "The `date_of_acquisition` field in LIMS " + f"({self.value}) for behavior session " + f"({session_id}) deviates by more " + f"than an hour from the `start_time` ({pkl_acq_date}) " + "specified in the associated stimulus *.pkl file: " + f"{stimulus_file.filepath}" + ) + return self diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/driver_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/driver_line.py new file mode 100644 index 000000000..acad1c32a --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/driver_line.py @@ -0,0 +1,51 @@ +from typing import List + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .lims_readable_mixin import \ + LimsReadableMixin +from allensdk.internal.api import PostgresQueryMixin, \ + OneOrMoreResultExpectedError + + +class DriverLine(DataObject, LimsReadableMixin): + """the genotype name(s) of the driver line(s)""" + def __init__(self, driver_line: List[str]): + super().__init__(name="driver_line", value=driver_line) + + @classmethod + def from_json(cls, dict_repr: dict) -> "DriverLine": + pass + + def to_json(self) -> dict: + return {"sex": self.value} + + @classmethod + def from_lims(cls, behavior_session_id: int, + lims_db: PostgresQueryMixin) -> "DriverLine": + query = f""" + SELECT g.name AS driver_line + FROM behavior_sessions bs + JOIN donors d ON bs.donor_id=d.id + JOIN donors_genotypes dg ON dg.donor_id=d.id + JOIN genotypes g ON g.id=dg.genotype_id + JOIN genotype_types gt + ON gt.id=g.genotype_type_id AND gt.name = 'driver' + WHERE bs.id={behavior_session_id}; + """ + result = lims_db.fetchall(query) + if result is None or len(result) < 1: + raise OneOrMoreResultExpectedError( + f"Expected one or more, but received: '{result}' " + f"from query:\n'{query}'") + driver_line = sorted(result) + return cls(driver_line=driver_line) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "DriverLine": + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass \ No newline at end of file diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py new file mode 100644 index 000000000..d6e54c61d --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py @@ -0,0 +1,36 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.internal.api import PostgresQueryMixin + + +class EquipmentName(DataObject): + """the name of the experimental rig.""" + def __init__(self, equipment_name: str): + super().__init__(name="equipment_name", value=equipment_name) + + @classmethod + def from_json(cls, dict_repr: dict) -> "EquipmentName": + return cls(equipment_name=dict_repr["equipment_name"]) + + def to_json(self) -> dict: + return {"eqipment_name": self.value} + + @classmethod + def from_lims(cls, behavior_session_id: int, + lims_db: PostgresQueryMixin) -> "EquipmentName": + query = f""" + SELECT e.name AS device_name + FROM behavior_sessions bs + JOIN equipment e ON e.id = bs.equipment_id + WHERE bs.id = {behavior_session_id}; + """ + equipment_name = lims_db.fetchone(query, strict=True) + return cls(equipment_name=equipment_name) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "EquipmentName": + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass \ No newline at end of file diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py new file mode 100644 index 000000000..af29f1d2b --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py @@ -0,0 +1,44 @@ +import uuid + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .lims_readable_mixin import \ + LimsReadableMixin +from allensdk.internal.api import PostgresQueryMixin + + +class ForagingId(DataObject, LimsReadableMixin): + """Foraging id""" + def __init__(self, foraging_id: uuid.UUID): + super().__init__(name="foraging_id", value=foraging_id) + + @classmethod + def from_json(cls, dict_repr: dict) -> "ForagingId": + pass + + def to_json(self) -> dict: + return {"sex": self.value} + + @classmethod + def from_lims(cls, behavior_session_id: int, + lims_db: PostgresQueryMixin) -> "ForagingId": + query = f""" + SELECT + foraging_id + FROM + behavior_sessions + WHERE + behavior_sessions.id = {behavior_session_id}; + """ + foraging_id = lims_db.fetchone(query, strict=True) + foraging_id = uuid.UUID(foraging_id) + return cls(foraging_id=foraging_id) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "ForagingId": + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass \ No newline at end of file diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/full_genotype.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/full_genotype.py new file mode 100644 index 000000000..ba966ea32 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/full_genotype.py @@ -0,0 +1,66 @@ +import warnings +from typing import Optional + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .lims_readable_mixin import \ + LimsReadableMixin +from allensdk.internal.api import PostgresQueryMixin + + +class FullGenotype(DataObject, LimsReadableMixin): + """the name of the subject's genotype""" + def __init__(self, full_genotype: str): + super().__init__(name="full_genotype", value=full_genotype) + + @classmethod + def from_json(cls, dict_repr: dict) -> "FullGenotype": + pass + + def to_json(self) -> dict: + return {"sex": self.value} + + @classmethod + def from_string(cls, full_genotype: str): + return cls(full_genotype=full_genotype) + + @classmethod + def from_lims(cls, behavior_session_id: int, + lims_db: PostgresQueryMixin) -> "FullGenotype": + query = f""" + SELECT d.full_genotype + FROM behavior_sessions bs + JOIN donors d ON d.id=bs.donor_id + WHERE bs.id= {behavior_session_id}; + """ + genotype = lims_db.fetchone(query, strict=True) + return cls(full_genotype=genotype) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "FullGenotype": + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass + + def parse_cre_line(self, warn=False) -> Optional[str]: + """ + Parameters + ---------- + warn + Whether to output warning if parsing fails + + Returns + ---------- + cre_line + just the Cre line, e.g. Vip-IRES-Cre, or None if not possible to + parse + """ + full_genotype = self.value + if ';' not in full_genotype: + if warn: + warnings.warn('Unable to parse cre_line from full_genotype') + return None + return full_genotype.split(';')[0].replace('/wt', '') diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/mouse_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/mouse_id.py new file mode 100644 index 000000000..46f3f764e --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/mouse_id.py @@ -0,0 +1,45 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .lims_readable_mixin import \ + LimsReadableMixin +from allensdk.internal.api import PostgresQueryMixin + + +class MouseId(DataObject, LimsReadableMixin): + """the LabTracks ID""" + def __init__(self, mouse_id: int): + super().__init__(name="mouse_id", value=mouse_id) + + @classmethod + def from_json(cls, dict_repr: dict) -> "MouseId": + pass + + def to_json(self) -> dict: + return {"sex": self.value} + + @classmethod + def from_lims(cls, behavior_session_id: int, + lims_db: PostgresQueryMixin) -> "MouseId": + # TODO: Should this even be included? + # Found sometimes there were entries with NONE which is + # why they are filtered out; also many entries in the table + # match the donor_id, which is why used DISTINCT + query = f""" + SELECT DISTINCT(sp.external_specimen_name) + FROM behavior_sessions bs + JOIN donors d ON bs.donor_id=d.id + JOIN specimens sp ON sp.donor_id=d.id + WHERE bs.id={behavior_session_id} + AND sp.external_specimen_name IS NOT NULL; + """ + mouse_id = int(lims_db.fetchone(query, strict=True)) + return cls(mouse_id=mouse_id) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "EquipmentName": + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass \ No newline at end of file diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/reporter_line.py new file mode 100644 index 000000000..69aaed088 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/reporter_line.py @@ -0,0 +1,117 @@ +import warnings +from typing import Optional, List + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .lims_readable_mixin import \ + LimsReadableMixin +from allensdk.internal.api import PostgresQueryMixin, \ + OneOrMoreResultExpectedError + + +class ReporterLine(DataObject, LimsReadableMixin): + """the genotype name(s) of the reporter line(s)""" + def __init__(self, reporter_line: Optional[str]): + super().__init__(name="reporter_line", value=reporter_line) + + @classmethod + def from_json(cls, dict_repr: dict) -> "ReporterLine": + pass + + def to_json(self) -> dict: + return {"sex": self.value} + + @classmethod + def from_lims(cls, behavior_session_id: int, + lims_db: PostgresQueryMixin) -> "ReporterLine": + query = f""" + SELECT g.name AS reporter_line + FROM behavior_sessions bs + JOIN donors d ON bs.donor_id=d.id + JOIN donors_genotypes dg ON dg.donor_id=d.id + JOIN genotypes g ON g.id=dg.genotype_id + JOIN genotype_types gt + ON gt.id=g.genotype_type_id AND gt.name = 'reporter' + WHERE bs.id={behavior_session_id}; + """ + result = lims_db.fetchall(query) + if result is None or len(result) < 1: + raise OneOrMoreResultExpectedError( + f"Expected one or more, but received: '{result}' " + f"from query:\n'{query}'") + reporter_line = cls._parse(reporter_line=result, warn=True) + return cls(reporter_line=reporter_line) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "ReporterLine": + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass + + @staticmethod + def _parse(reporter_line: Optional[List[str]], + warn=False) -> Optional[str]: + """There can be multiple reporter lines, so it is returned from LIMS + as a list. But there shouldn't be more than 1 for behavior. This + tries to convert to str + + Parameters + ---------- + reporter_line + List of reporter line + warn + Whether to output warnings if parsing fails + + Returns + --------- + single reporter line, or None if not possible + """ + if reporter_line is None: + if warn: + warnings.warn('Error parsing reporter line. It is null.') + return None + + if len(reporter_line) == 0: + if warn: + warnings.warn('Error parsing reporter line. ' + 'The array is empty') + return None + + if isinstance(reporter_line, str): + return reporter_line + + if len(reporter_line) > 1: + if warn: + warnings.warn('More than 1 reporter line. Returning the first ' + 'one') + + return reporter_line[0] + + @property + def indicator(self, warn=False) -> Optional[str]: + """Parses indicator from reporter""" + reporter_line = self.value + reporter_substring_indicator_map = { + 'GCaMP6f': 'GCaMP6f', + 'GC6f': 'GCaMP6f', + 'GCaMP6s': 'GCaMP6s' + } + if reporter_line is None: + if warn: + warnings.warn( + 'Could not parse indicator from reporter because ' + 'there is no reporter') + return None + + for substr, indicator in reporter_substring_indicator_map.items(): + if substr in reporter_line: + return indicator + + if warn: + warnings.warn( + 'Could not parse indicator from reporter because none' + 'of the expected substrings were found in the reporter') + return None diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py new file mode 100644 index 000000000..68a4323c6 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py @@ -0,0 +1,49 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .stimulus_file_readable_mixin \ + import \ + StimulusFileReadableMixin + + +class SessionType(DataObject, StimulusFileReadableMixin): + """the stimulus set used""" + def __init__(self, session_type: str): + super().__init__(name="session_type", value=session_type) + + @classmethod + def from_json(cls, dict_repr: dict) -> None: + raise NotImplementedError() + + def to_json(self) -> dict: + return {"sex": self.value} + + @classmethod + def from_lims(cls) -> None: + raise NotImplementedError() + + @classmethod + def from_stimulus_file( + cls, + stimulus_file: StimulusFile) -> "SessionType": + try: + stimulus_name = \ + stimulus_file.data["items"]["behavior"]["cl_params"]["stage"] + except KeyError: + raise RuntimeError( + f"Could not obtain stimulus_name/stage information from " + f"the *.pkl file ({stimulus_file.filepath}) " + f"for the behavior session to save as NWB! The " + f"following series of nested keys did not work: " + f"['items']['behavior']['cl_params']['stage']" + ) + return cls(session_type=stimulus_name) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "SessionType": + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/sex.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/sex.py new file mode 100644 index 000000000..c52a2a80a --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/sex.py @@ -0,0 +1,40 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .lims_readable_mixin import \ + LimsReadableMixin +from allensdk.internal.api import PostgresQueryMixin + + +class Sex(DataObject, LimsReadableMixin): + """sex of the animal (M/F)""" + def __init__(self, sex: str): + super().__init__(name="sex", value=sex) + + @classmethod + def from_json(cls, dict_repr: dict) -> "Sex": + return cls(sex=dict_repr["sex"]) + + def to_json(self) -> dict: + return {"sex": self.value} + + @classmethod + def from_lims(cls, behavior_session_id: int, + lims_db: PostgresQueryMixin) -> "Sex": + query = f""" + SELECT g.name AS sex + FROM behavior_sessions bs + JOIN donors d ON bs.donor_id = d.id + JOIN genders g ON g.id = d.gender_id + WHERE bs.id = {behavior_session_id}; + """ + sex = lims_db.fetchone(query, strict=True) + return cls(sex=sex) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "EquipmentName": + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass \ No newline at end of file diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py new file mode 100644 index 000000000..9c60e8a2f --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py @@ -0,0 +1,31 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject, \ + StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .stimulus_file_readable_mixin \ + import \ + StimulusFileReadableMixin + + +class StimulusFrameRate(DataObject, StimulusFileReadableMixin): + """Stimulus frame rate""" + def __init__(self, stimulus_frame_rate: float): + super().__init__(name="stimulus_frame_rate", value=stimulus_frame_rate) + + def to_json(self) -> dict: + return {"stimulus_frame_rate": self.value} + + @classmethod + def from_stimulus_file( + cls, + stimulus_timestamps: StimulusTimestamps) -> "StimulusFrameRate": + frame_rate = stimulus_timestamps.calc_frame_rate() + return cls(stimulus_frame_rate=frame_rate) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "StimulusFrameRate": + pass + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + pass \ No newline at end of file diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/__init__.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py index 6c4905075..d5de10277 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py @@ -117,8 +117,8 @@ def from_lims( ) -> "RunningAcquisition": stimulus_file = StimulusFile.from_lims(db, behavior_session_id) - stimulus_timestamps = StimulusTimestamps.from_lims( - db, behavior_session_id, ophys_experiment_id + stimulus_timestamps = StimulusTimestamps.from_stimulus_file( + stimulus_file=stimulus_file ) running_acq_df = get_running_df( data=stimulus_file.data, time=stimulus_timestamps.value, diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py index 652a170bf..c3fe6bbe8 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py @@ -129,8 +129,8 @@ def from_lims( zscore_threshold: float = 10.0 ) -> "RunningSpeed": stimulus_file = StimulusFile.from_lims(db, behavior_session_id) - stimulus_timestamps = StimulusTimestamps.from_lims( - db, behavior_session_id, ophys_experiment_id + stimulus_timestamps = StimulusTimestamps.from_stimulus_file( + stimulus_file=stimulus_file ) running_speed = cls._get_running_speed_df( diff --git a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py index ab77f086e..0293c3ab2 100644 --- a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py +++ b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py @@ -2,14 +2,19 @@ import json from typing import Optional -from cachetools import cached, LRUCache from cachetools.keys import hashkey import numpy as np from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries -from allensdk.internal.api import PostgresQueryMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .stimulus_file_readable_mixin \ + import \ + StimulusFileReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .sync_file_readable_mixin import \ + SyncFileReadableMixin from allensdk.brain_observatory.behavior.data_objects import DataObject from allensdk.brain_observatory.behavior.data_files import ( StimulusFile, SyncFile @@ -30,7 +35,8 @@ def from_lims_cache_key( return hashkey(behavior_session_id, ophys_experiment_id) -class StimulusTimestamps(DataObject): +class StimulusTimestamps(DataObject, StimulusFileReadableMixin, + SyncFileReadableMixin): """A DataObject which contains properties and methods to load, process, and represent visual behavior stimulus timestamp data. @@ -51,24 +57,25 @@ def __init__( self._sync_file = sync_file @classmethod - @cached(cache=LRUCache(maxsize=10), key=from_json_cache_key) - def from_json(cls, dict_repr: dict) -> "StimulusTimestamps": - stimulus_file = StimulusFile.from_json(dict_repr) - - if "sync_file" in dict_repr: - sync_file = SyncFile.from_json(dict_repr) - stimulus_timestamps = get_ophys_stimulus_timestamps( - sync_path=sync_file.filepath - ) - else: - sync_file = None - stimulus_timestamps = get_behavior_stimulus_timestamps( - stimulus_pkl=stimulus_file.data - ) + def from_stimulus_file( + cls, + stimulus_file: StimulusFile) -> "StimulusTimestamps": + stimulus_timestamps = get_behavior_stimulus_timestamps( + stimulus_pkl=stimulus_file.data + ) + + return cls( + timestamps=stimulus_timestamps, + stimulus_file=stimulus_file + ) + @classmethod + def from_sync_file(cls, sync_file: SyncFile) -> "StimulusTimestamps": + stimulus_timestamps = get_ophys_stimulus_timestamps( + sync_path=sync_file.filepath + ) return cls( timestamps=stimulus_timestamps, - stimulus_file=stimulus_file, sync_file=sync_file ) @@ -86,33 +93,6 @@ def to_json(self) -> dict: output_dict.update(self._sync_file.to_json()) return output_dict - @classmethod - @cached(cache=LRUCache(maxsize=10), key=from_lims_cache_key) - def from_lims( - cls, - db: PostgresQueryMixin, - behavior_session_id: int, - ophys_experiment_id: Optional[int] = None - ) -> "StimulusTimestamps": - stimulus_file = StimulusFile.from_lims(db, behavior_session_id) - - if ophys_experiment_id: - sync_file = SyncFile.from_lims(db, ophys_experiment_id) - stimulus_timestamps = get_ophys_stimulus_timestamps( - sync_path=sync_file.filepath - ) - else: - sync_file = None - stimulus_timestamps = get_behavior_stimulus_timestamps( - stimulus_pkl=stimulus_file.data - ) - - return cls( - timestamps=stimulus_timestamps, - stimulus_file=stimulus_file, - sync_file=sync_file - ) - @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "StimulusTimestamps": stim_module = nwbfile.processing["stimulus"] @@ -133,3 +113,6 @@ def to_nwb(self, nwbfile: NWBFile) -> NWBFile: nwbfile.add_processing_module(stim_mod) return nwbfile + + def calc_frame_rate(self): + return np.round(1 / np.mean(np.diff(self.value)), 0) diff --git a/allensdk/brain_observatory/behavior/metadata/behavior_ophys_metadata.py b/allensdk/brain_observatory/behavior/metadata/behavior_ophys_metadata.py index b2c597cad..63779a3b3 100644 --- a/allensdk/brain_observatory/behavior/metadata/behavior_ophys_metadata.py +++ b/allensdk/brain_observatory/behavior/metadata/behavior_ophys_metadata.py @@ -1,7 +1,8 @@ import numpy as np from typing import Optional -from allensdk.brain_observatory.behavior.metadata.behavior_metadata import \ +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ BehaviorMetadata from allensdk.brain_observatory.behavior.session_apis.abcs.\ data_extractor_base.behavior_ophys_data_extractor_base import \ diff --git a/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_base.py b/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_base.py index 3a3411af9..a967c84aa 100644 --- a/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_base.py +++ b/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_base.py @@ -4,7 +4,8 @@ import numpy as np import pandas as pd -from allensdk.brain_observatory.behavior.metadata.behavior_metadata import \ +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ BehaviorMetadata from allensdk.brain_observatory.behavior.stimulus_processing import \ StimulusTemplate diff --git a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py index 59345079a..0548abe1e 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py @@ -9,7 +9,8 @@ from pynwb import NWBHDF5IO, NWBFile import allensdk.brain_observatory.nwb as nwb -from allensdk.brain_observatory.behavior.metadata.behavior_metadata import ( +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import ( get_expt_description, BehaviorMetadata ) from allensdk.brain_observatory.behavior.session_apis.abcs.\ diff --git a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py index 84789ffb1..def0cfe3c 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py @@ -16,7 +16,8 @@ from allensdk.brain_observatory.behavior.event_detection import \ filter_events_array import allensdk.brain_observatory.nwb as nwb -from allensdk.brain_observatory.behavior.metadata.behavior_metadata import ( +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import ( get_expt_description ) from allensdk.brain_observatory.behavior.session_apis.abcs.session_base. \ diff --git a/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py b/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py index daf8ed43a..063a4fa4b 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py @@ -5,7 +5,8 @@ import numpy as np import pandas as pd import os -from allensdk.brain_observatory.behavior.metadata.behavior_metadata import \ +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ get_task_parameters, BehaviorMetadata from allensdk.api.warehouse_cache.cache import memoize from allensdk.internal.core.lims_utilities import safe_system_path diff --git a/allensdk/brain_observatory/behavior/swdb/behavior_project_cache.py b/allensdk/brain_observatory/behavior/swdb/behavior_project_cache.py index e34e9b214..9c63015f5 100644 --- a/allensdk/brain_observatory/behavior/swdb/behavior_project_cache.py +++ b/allensdk/brain_observatory/behavior/swdb/behavior_project_cache.py @@ -5,7 +5,8 @@ import re from allensdk import one -from allensdk.brain_observatory.behavior.metadata.behavior_metadata import \ +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ BehaviorMetadata from allensdk.brain_observatory.behavior.session_apis.data_io import ( BehaviorOphysNwbApi) diff --git a/allensdk/test/brain_observatory/behavior/behavior_project_cache/test-reports/test.xml b/allensdk/test/brain_observatory/behavior/behavior_project_cache/test-reports/test.xml new file mode 100644 index 000000000..33eb7abd3 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/behavior_project_cache/test-reports/test.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/allensdk/test/brain_observatory/behavior/test-reports/test.xml b/allensdk/test/brain_observatory/behavior/test-reports/test.xml new file mode 100644 index 000000000..5662099d8 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/test-reports/test.xml @@ -0,0 +1,1294 @@ +/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:22: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:22: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:45: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:54: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:65: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:65: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:65: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightlyMockBehaviorLimsApi = <test_behavior_lims_api.MockBehaviorLimsApi.<locals>.MockBehaviorLimsApi object at 0x7fce99c359d0>, monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99c35510> + + def test_get_behavior_session_uuid(MockBehaviorLimsApi, monkeypatch): + with monkeypatch.context() as ctx: + def dummy_init(self, extractor, behavior_stimulus_file): + self._extractor = extractor + self._behavior_stimulus_file = behavior_stimulus_file + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + stimulus_file = MockBehaviorLimsApi._behavior_stimulus_file() + metadata = BehaviorMetadata( + extractor=MockBehaviorLimsApi.extractor, + behavior_stimulus_file=stimulus_file) + + expected = UUID('138531ab-fe59-4523-9154-07c8d97bbe03') +> assert expected == metadata.behavior_session_uuid + +test_behavior_lims_api.py:232: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99c358d0> + + @property + def behavior_session_uuid(self) -> Optional[uuid.UUID]: +> return self._behavior_session_uuid.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_behavior_session_uuid' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:330: AttributeErrorMockBehaviorLimsApi = <test_behavior_lims_api.MockBehaviorLimsApi.<locals>.MockBehaviorLimsApi object at 0x7fce99bd0550> + + def test_get_date_of_acquisition(MockBehaviorLimsApi): + api = MockBehaviorLimsApi + expected = datetime(2019, 9, 26, 16, tzinfo=pytz.UTC) +> actual = api.get_metadata().date_of_acquisition + +test_behavior_lims_api.py:243: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <test_behavior_lims_api.MockBehaviorLimsApi.<locals>.MockBehaviorLimsApi object at 0x7fce99bd0550> + + def get_metadata(self) -> BehaviorMetadata: + """Return metadata about the session. + :rtype: BehaviorMetadata + """ + metadata = BehaviorMetadata( + extractor=self.extractor, + stimulus_timestamps=self.get_stimulus_timestamps(), +> behavior_stimulus_file=self._behavior_stimulus_file() + ) +E TypeError: __init__() got an unexpected keyword argument 'extractor' + +../../../brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py:351: TypeError/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:292: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:296: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:301: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:305: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:309: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:313: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:317: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:326: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:335: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:342: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:357: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:373: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:385: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:388: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:392: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:396: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:400: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:404: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:408: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:412: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds).monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99b7c810> + + def test_cre_line(monkeypatch): + """Tests that cre_line properly parsed from driver_line""" + with monkeypatch.context() as ctx: + def dummy_init(self): + pass + + def full_genotype(self): + return 'Sst-IRES-Cre/wt;Ai148(TIT2L-GC6f-ICL-tTA2)/wt' + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + ctx.setattr(BehaviorMetadata, + 'full_genotype', + property(full_genotype)) + + metadata = BehaviorMetadata() + +> assert metadata.cre_line == 'Sst-IRES-Cre' + +test_behavior_metadata.py:346: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99b7c7d0> + + @property + def cre_line(self) -> Optional[str]: +> return self._full_genotype.parse_cre_line(warn=True) +E AttributeError: 'BehaviorMetadata' object has no attribute '_full_genotype' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:326: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99ad5290> + + def test_cre_line_bad_full_genotype(monkeypatch): + """Test that cre_line is None and no error raised""" + with monkeypatch.context() as ctx: + def dummy_init(self): + pass + + def full_genotype(self): + return 'foo' + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + ctx.setattr(BehaviorMetadata, + 'full_genotype', + property(full_genotype)) + + metadata = BehaviorMetadata() + + with pytest.warns(UserWarning) as record: +> cre_line = metadata.cre_line + +test_behavior_metadata.py:368: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99ad5390> + + @property + def cre_line(self) -> Optional[str]: +> return self._full_genotype.parse_cre_line(warn=True) +E AttributeError: 'BehaviorMetadata' object has no attribute '_full_genotype' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:326: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99b7c6d0> + + def test_reporter_line(monkeypatch): + """Test that reporter line properly parsed from list""" + + class MockExtractor: + def get_reporter_line(self): + return ['foo'] + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self): + self._extractor = extractor + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + + metadata = BehaviorMetadata() + +> assert metadata.reporter_line == 'foo' + +test_behavior_metadata.py:393: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99b7c150> + + @property + def reporter_line(self) -> Optional[str]: +> return self._reporter_line.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:314: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99add250> + + def test_reporter_line_str(monkeypatch): + """Test that reporter line returns itself if str""" + + class MockExtractor: + def get_reporter_line(self): + return 'foo' + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self): + self._extractor = extractor + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + + metadata = BehaviorMetadata() + +> assert metadata.reporter_line == 'foo' + +test_behavior_metadata.py:415: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99add510> + + @property + def reporter_line(self) -> Optional[str]: +> return self._reporter_line.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:314: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99add390>, input_reporter_line = ('foo', 'bar'), warning_msg = 'More than 1 reporter line. Returning the first one', expected = 'foo' + + @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( + (('foo', 'bar'), 'More than 1 reporter line. ' + 'Returning the first one', 'foo'), + (None, 'Error parsing reporter line. It is null.', None), + ([], 'Error parsing reporter line. The array is empty', None) + ) + ) + def test_reporter_edge_cases(monkeypatch, input_reporter_line, warning_msg, + expected): + """Test reporter line edge cases""" + + class MockExtractor: + def get_reporter_line(self): + return input_reporter_line + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self): + self._extractor = extractor + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + metadata = BehaviorMetadata() + + with pytest.warns(UserWarning) as record: +> reporter_line = metadata.reporter_line + +test_behavior_metadata.py:445: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99add9d0> + + @property + def reporter_line(self) -> Optional[str]: +> return self._reporter_line.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:314: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99add290>, input_reporter_line = None, warning_msg = 'Error parsing reporter line. It is null.', expected = None + + @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( + (('foo', 'bar'), 'More than 1 reporter line. ' + 'Returning the first one', 'foo'), + (None, 'Error parsing reporter line. It is null.', None), + ([], 'Error parsing reporter line. The array is empty', None) + ) + ) + def test_reporter_edge_cases(monkeypatch, input_reporter_line, warning_msg, + expected): + """Test reporter line edge cases""" + + class MockExtractor: + def get_reporter_line(self): + return input_reporter_line + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self): + self._extractor = extractor + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + metadata = BehaviorMetadata() + + with pytest.warns(UserWarning) as record: +> reporter_line = metadata.reporter_line + +test_behavior_metadata.py:445: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a562d0> + + @property + def reporter_line(self) -> Optional[str]: +> return self._reporter_line.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:314: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a56ed0>, input_reporter_line = [], warning_msg = 'Error parsing reporter line. The array is empty', expected = None + + @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( + (('foo', 'bar'), 'More than 1 reporter line. ' + 'Returning the first one', 'foo'), + (None, 'Error parsing reporter line. It is null.', None), + ([], 'Error parsing reporter line. The array is empty', None) + ) + ) + def test_reporter_edge_cases(monkeypatch, input_reporter_line, warning_msg, + expected): + """Test reporter line edge cases""" + + class MockExtractor: + def get_reporter_line(self): + return input_reporter_line + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self): + self._extractor = extractor + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + metadata = BehaviorMetadata() + + with pytest.warns(UserWarning) as record: +> reporter_line = metadata.reporter_line + +test_behavior_metadata.py:445: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a6f150> + + @property + def reporter_line(self) -> Optional[str]: +> return self._reporter_line.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:314: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a6ffd0> + + def test_age_in_days(monkeypatch): + """Test that age_in_days properly parsed from age""" + + class MockExtractor: + def get_age(self): + return 'P123' + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self): + self._extractor = extractor + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + + metadata = BehaviorMetadata() + +> assert metadata.age_in_days == 123 + +test_behavior_metadata.py:470: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a6ff10> + + @property + def age_in_days(self) -> Optional[int]: +> return self._age.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_age' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:298: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a6f910>, input_age = 'unkown', warning_msg = 'Could not parse numeric age from age code (age code does not start with "P")', expected = None + + @pytest.mark.parametrize("input_age, warning_msg, expected", ( + ('unkown', 'Could not parse numeric age from age code ' + '(age code does not start with "P")', None), + ('P', 'Could not parse numeric age from age code ' + '(no numeric values found in age code)', None) + ) + ) + def test_age_in_days_edge_cases(monkeypatch, input_age, warning_msg, + expected): + """Test age in days edge cases""" + + class MockExtractor: + def get_age(self): + return input_age + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self): + self._extractor = extractor + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + + metadata = BehaviorMetadata() + + with pytest.warns(UserWarning) as record: +> age_in_days = metadata.age_in_days + +test_behavior_metadata.py:501: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a6d750> + + @property + def age_in_days(self) -> Optional[int]: +> return self._age.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_age' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:298: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a6dd50>, input_age = 'P', warning_msg = 'Could not parse numeric age from age code (no numeric values found in age code)', expected = None + + @pytest.mark.parametrize("input_age, warning_msg, expected", ( + ('unkown', 'Could not parse numeric age from age code ' + '(age code does not start with "P")', None), + ('P', 'Could not parse numeric age from age code ' + '(no numeric values found in age code)', None) + ) + ) + def test_age_in_days_edge_cases(monkeypatch, input_age, warning_msg, + expected): + """Test age in days edge cases""" + + class MockExtractor: + def get_age(self): + return input_age + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self): + self._extractor = extractor + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + + metadata = BehaviorMetadata() + + with pytest.warns(UserWarning) as record: +> age_in_days = metadata.age_in_days + +test_behavior_metadata.py:501: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a6d110> + + @property + def age_in_days(self) -> Optional[int]: +> return self._age.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_age' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:298: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a634d0>, tmp_path = PosixPath('/tmp/pytest-of-adam.amster/pytest-0/test_get_date_of_acquisition_t0') +test_params = {'behavior_session_id': 1, 'extractor_expt_date': datetime.datetime(2021, 3, 14, 3, 14, 15), 'pkl_expt_date': datetime.datetime(2021, 3, 14, 3, 14, 15)}, expected_warn_msg = None + + @pytest.mark.parametrize("test_params, expected_warn_msg", [ + # Vanilla test case + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "behavior_session_id": 1 + }, None), + + # pkl expt date stored in unix format + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": 1615716855.0, + "behavior_session_id": 2 + }, None), + + # Extractor and pkl dates differ significantly + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": datetime.strptime("2021-03-14 20:14:15", + "%Y-%m-%d %H:%M:%S"), + "behavior_session_id": 3 + }, + "The `date_of_acquisition` field in LIMS *"), + + # pkl file contains an unparseable datetime + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": None, + "behavior_session_id": 4 + }, + "Could not parse the acquisition datetime *"), + ]) + def test_get_date_of_acquisition(monkeypatch, tmp_path, test_params, + expected_warn_msg): + mock_session_id = test_params["behavior_session_id"] + + pkl_save_path = tmp_path / f"mock_pkl_{mock_session_id}.pkl" + with open(pkl_save_path, 'wb') as handle: + pickle.dump({"start_time": test_params['pkl_expt_date']}, handle) + behavior_stimulus_file = pd.read_pickle(pkl_save_path) + + tz = pytz.timezone("America/Los_Angeles") + extractor_expt_date = tz.localize( + test_params['extractor_expt_date']).astimezone(pytz.utc) + + class MockExtractor(): + def get_date_of_acquisition(self): + return extractor_expt_date + + def get_behavior_session_id(self): + return test_params['behavior_session_id'] + + def get_behavior_stimulus_file(self): + return pkl_save_path + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self, extractor, behavior_stimulus_file): + self._extractor = extractor + self._behavior_stimulus_file = behavior_stimulus_file + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + + metadata = BehaviorMetadata( + extractor=extractor, + behavior_stimulus_file=behavior_stimulus_file) + + if expected_warn_msg: + with pytest.warns(Warning, match=expected_warn_msg): + obt_date = metadata.date_of_acquisition + else: +> obt_date = metadata.date_of_acquisition + +test_behavior_metadata.py:586: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fcf01f2b9d0> + + @property + def date_of_acquisition(self) -> datetime: +> return self._date_of_acquisition.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_date_of_acquisition' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:310: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a84f90>, tmp_path = PosixPath('/tmp/pytest-of-adam.amster/pytest-0/test_get_date_of_acquisition_t1') +test_params = {'behavior_session_id': 2, 'extractor_expt_date': datetime.datetime(2021, 3, 14, 3, 14, 15), 'pkl_expt_date': 1615716855.0}, expected_warn_msg = None + + @pytest.mark.parametrize("test_params, expected_warn_msg", [ + # Vanilla test case + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "behavior_session_id": 1 + }, None), + + # pkl expt date stored in unix format + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": 1615716855.0, + "behavior_session_id": 2 + }, None), + + # Extractor and pkl dates differ significantly + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": datetime.strptime("2021-03-14 20:14:15", + "%Y-%m-%d %H:%M:%S"), + "behavior_session_id": 3 + }, + "The `date_of_acquisition` field in LIMS *"), + + # pkl file contains an unparseable datetime + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": None, + "behavior_session_id": 4 + }, + "Could not parse the acquisition datetime *"), + ]) + def test_get_date_of_acquisition(monkeypatch, tmp_path, test_params, + expected_warn_msg): + mock_session_id = test_params["behavior_session_id"] + + pkl_save_path = tmp_path / f"mock_pkl_{mock_session_id}.pkl" + with open(pkl_save_path, 'wb') as handle: + pickle.dump({"start_time": test_params['pkl_expt_date']}, handle) + behavior_stimulus_file = pd.read_pickle(pkl_save_path) + + tz = pytz.timezone("America/Los_Angeles") + extractor_expt_date = tz.localize( + test_params['extractor_expt_date']).astimezone(pytz.utc) + + class MockExtractor(): + def get_date_of_acquisition(self): + return extractor_expt_date + + def get_behavior_session_id(self): + return test_params['behavior_session_id'] + + def get_behavior_stimulus_file(self): + return pkl_save_path + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self, extractor, behavior_stimulus_file): + self._extractor = extractor + self._behavior_stimulus_file = behavior_stimulus_file + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + + metadata = BehaviorMetadata( + extractor=extractor, + behavior_stimulus_file=behavior_stimulus_file) + + if expected_warn_msg: + with pytest.warns(Warning, match=expected_warn_msg): + obt_date = metadata.date_of_acquisition + else: +> obt_date = metadata.date_of_acquisition + +test_behavior_metadata.py:586: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a84950> + + @property + def date_of_acquisition(self) -> datetime: +> return self._date_of_acquisition.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_date_of_acquisition' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:310: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a84fd0>, tmp_path = PosixPath('/tmp/pytest-of-adam.amster/pytest-0/test_get_date_of_acquisition_t2') +test_params = {'behavior_session_id': 3, 'extractor_expt_date': datetime.datetime(2021, 3, 14, 3, 14, 15), 'pkl_expt_date': datetime.datetime(2021, 3, 14, 20, 14, 15)}, expected_warn_msg = 'The `date_of_acquisition` field in LIMS *' + + @pytest.mark.parametrize("test_params, expected_warn_msg", [ + # Vanilla test case + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "behavior_session_id": 1 + }, None), + + # pkl expt date stored in unix format + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": 1615716855.0, + "behavior_session_id": 2 + }, None), + + # Extractor and pkl dates differ significantly + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": datetime.strptime("2021-03-14 20:14:15", + "%Y-%m-%d %H:%M:%S"), + "behavior_session_id": 3 + }, + "The `date_of_acquisition` field in LIMS *"), + + # pkl file contains an unparseable datetime + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": None, + "behavior_session_id": 4 + }, + "Could not parse the acquisition datetime *"), + ]) + def test_get_date_of_acquisition(monkeypatch, tmp_path, test_params, + expected_warn_msg): + mock_session_id = test_params["behavior_session_id"] + + pkl_save_path = tmp_path / f"mock_pkl_{mock_session_id}.pkl" + with open(pkl_save_path, 'wb') as handle: + pickle.dump({"start_time": test_params['pkl_expt_date']}, handle) + behavior_stimulus_file = pd.read_pickle(pkl_save_path) + + tz = pytz.timezone("America/Los_Angeles") + extractor_expt_date = tz.localize( + test_params['extractor_expt_date']).astimezone(pytz.utc) + + class MockExtractor(): + def get_date_of_acquisition(self): + return extractor_expt_date + + def get_behavior_session_id(self): + return test_params['behavior_session_id'] + + def get_behavior_stimulus_file(self): + return pkl_save_path + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self, extractor, behavior_stimulus_file): + self._extractor = extractor + self._behavior_stimulus_file = behavior_stimulus_file + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + + metadata = BehaviorMetadata( + extractor=extractor, + behavior_stimulus_file=behavior_stimulus_file) + + if expected_warn_msg: + with pytest.warns(Warning, match=expected_warn_msg): +> obt_date = metadata.date_of_acquisition + +test_behavior_metadata.py:584: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fcf01f2b910> + + @property + def date_of_acquisition(self) -> datetime: +> return self._date_of_acquisition.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_date_of_acquisition' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:310: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a4fe90>, tmp_path = PosixPath('/tmp/pytest-of-adam.amster/pytest-0/test_get_date_of_acquisition_t3') +test_params = {'behavior_session_id': 4, 'extractor_expt_date': datetime.datetime(2021, 3, 14, 3, 14, 15), 'pkl_expt_date': None}, expected_warn_msg = 'Could not parse the acquisition datetime *' + + @pytest.mark.parametrize("test_params, expected_warn_msg", [ + # Vanilla test case + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "behavior_session_id": 1 + }, None), + + # pkl expt date stored in unix format + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": 1615716855.0, + "behavior_session_id": 2 + }, None), + + # Extractor and pkl dates differ significantly + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": datetime.strptime("2021-03-14 20:14:15", + "%Y-%m-%d %H:%M:%S"), + "behavior_session_id": 3 + }, + "The `date_of_acquisition` field in LIMS *"), + + # pkl file contains an unparseable datetime + ({ + "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": None, + "behavior_session_id": 4 + }, + "Could not parse the acquisition datetime *"), + ]) + def test_get_date_of_acquisition(monkeypatch, tmp_path, test_params, + expected_warn_msg): + mock_session_id = test_params["behavior_session_id"] + + pkl_save_path = tmp_path / f"mock_pkl_{mock_session_id}.pkl" + with open(pkl_save_path, 'wb') as handle: + pickle.dump({"start_time": test_params['pkl_expt_date']}, handle) + behavior_stimulus_file = pd.read_pickle(pkl_save_path) + + tz = pytz.timezone("America/Los_Angeles") + extractor_expt_date = tz.localize( + test_params['extractor_expt_date']).astimezone(pytz.utc) + + class MockExtractor(): + def get_date_of_acquisition(self): + return extractor_expt_date + + def get_behavior_session_id(self): + return test_params['behavior_session_id'] + + def get_behavior_stimulus_file(self): + return pkl_save_path + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self, extractor, behavior_stimulus_file): + self._extractor = extractor + self._behavior_stimulus_file = behavior_stimulus_file + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + + metadata = BehaviorMetadata( + extractor=extractor, + behavior_stimulus_file=behavior_stimulus_file) + + if expected_warn_msg: + with pytest.warns(Warning, match=expected_warn_msg): +> obt_date = metadata.date_of_acquisition + +test_behavior_metadata.py:584: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a4f490> + + @property + def date_of_acquisition(self) -> datetime: +> return self._date_of_acquisition.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_date_of_acquisition' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:310: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a4f050> + + def test_indicator(monkeypatch): + """Test that indicator is parsed from full_genotype""" + + class MockExtractor: + def get_reporter_line(self): + return 'Ai148(TIT2L-GC6f-ICL-tTA2)' + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self): + self._extractor = extractor + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + + metadata = BehaviorMetadata() + +> assert metadata.indicator == 'GCaMP6f' + +test_behavior_metadata.py:610: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a818d0> + + @property + def indicator(self) -> Optional[str]: +> return self._reporter_line.indicator +E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:318: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a81b10>, input_reporter_line = None, warning_msg = 'Error parsing reporter line. It is null.', expected = None + + @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( + (None, 'Error parsing reporter line. It is null.', None), + ('foo', 'Could not parse indicator from reporter because none' + 'of the expected substrings were found in the reporter', None) + ) + ) + def test_indicator_edge_cases(monkeypatch, input_reporter_line, warning_msg, + expected): + """Test indicator parsing edge cases""" + + class MockExtractor: + def get_reporter_line(self): + return input_reporter_line + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self): + self._extractor = extractor + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + + metadata = BehaviorMetadata() + + with pytest.warns(UserWarning) as record: +> indicator = metadata.indicator + +test_behavior_metadata.py:640: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a815d0> + + @property + def indicator(self) -> Optional[str]: +> return self._reporter_line.indicator +E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:318: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99ab1dd0>, input_reporter_line = 'foo', warning_msg = 'Could not parse indicator from reporter because noneof the expected substrings were found in the reporter' +expected = None + + @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( + (None, 'Error parsing reporter line. It is null.', None), + ('foo', 'Could not parse indicator from reporter because none' + 'of the expected substrings were found in the reporter', None) + ) + ) + def test_indicator_edge_cases(monkeypatch, input_reporter_line, warning_msg, + expected): + """Test indicator parsing edge cases""" + + class MockExtractor: + def get_reporter_line(self): + return input_reporter_line + + extractor = MockExtractor() + + with monkeypatch.context() as ctx: + def dummy_init(self): + self._extractor = extractor + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_init) + + metadata = BehaviorMetadata() + + with pytest.warns(UserWarning) as record: +> indicator = metadata.indicator + +test_behavior_metadata.py:640: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99ab1fd0> + + @property + def indicator(self) -> Optional[str]: +> return self._reporter_line.indicator +E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:318: AttributeErrorself = <allensdk.brain_observatory.behavior.session_apis.data_transforms.behavior_ophys_data_transforms.BehaviorOphysDataTransforms object at 0x7fce9b1abfd0> + + def _load_stimulus_timestamps_and_delay(self): + """ + Load the stimulus timestamps (uncorrected for + monitor delay) and the monitor delay + """ + sync_path = self.extractor.get_sync_file() + aligner = OphysTimeAligner(sync_file=sync_path) + (self._stimulus_timestamps, + delta) = aligner.clipped_stim_timestamps + + try: +> delay = aligner.monitor_delay + +../../../brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py:163: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.internal.brain_observatory.time_sync.OphysTimeAligner object at 0x7fce9b1ab350> + + @property + def monitor_delay(self): + """ + The monitor delay (in seconds) associated with the session + """ + if self._monitor_delay is None: +> self._monitor_delay = self._get_monitor_delay() + +../../../internal/brain_observatory/time_sync.py:393: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.internal.brain_observatory.time_sync.OphysTimeAligner object at 0x7fce9b1ab350> + + def dummy_delay(self): +> raise ValueError("that did not work") +E ValueError: that did not work + +test_behavior_ophys_data_xforms.py:431: ValueError + +During handling of the above exception, another exception occurred: + +monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a6d6d0> + + def test_monitor_delay(monkeypatch): + """ + Check that BehaviorOphysDataTransforms can handle all + edge cases of monitor delay calculation + """ + + # first test case where monitor delay calculation succeeds + class DummyExtractor(object): + def get_sync_file(self): + return '' + + def get_equipment_name(self): + return 'spam' + + def xform_init(self): + self.extractor = DummyExtractor() + + def aligner_init(self, sync_file=None): + self._monitor_delay = None + self._clipped_stim_ts_delta = None + + def dummy_clipped(self): + return np.array([1, 2, 3, 4, 5], dtype=int), -1 + + def dummy_delay(self): + return 1.12 + + with monkeypatch.context() as ctx: + ctx.setattr(BehaviorOphysDataTransforms, + '__init__', + xform_init) + + ctx.setattr(OphysTimeAligner, + '__init__', + aligner_init) + + ctx.setattr(OphysTimeAligner, + '_get_clipped_stim_timestamps', + dummy_clipped) + + ctx.setattr(OphysTimeAligner, + '_get_monitor_delay', + dummy_delay) + + xforms = BehaviorOphysDataTransforms() + assert abs(xforms.get_monitor_delay() - 1.12) < 1.0e-6 + np.testing.assert_array_equal(xforms.get_stimulus_timestamps(), + np.array([1, 2, 3, 4, 5], dtype=int)) + + # now try case where monitor delay fails, but value can + # be looked up + def dummy_delay(self): + raise ValueError("that did not work") + + delay_lookup = {'CAM2P.1': 0.020842, + 'CAM2P.2': 0.037566, + 'CAM2P.3': 0.021390, + 'CAM2P.4': 0.021102, + 'CAM2P.5': 0.021192, + 'MESO.1': 0.03613} + + def dummy_get_metadata(self): + def dummy_metadata_init(self, extractor): + self._extractor = extractor + + ctx.setattr(BehaviorMetadata, + '__init__', + dummy_metadata_init) + + class DummyExtractor: + def get_sync_file(self): + return '' + + def get_equipment_name(self): + return equipment_name + + metadata = BehaviorMetadata( + extractor=DummyExtractor()) + return metadata + + for equipment_name in delay_lookup.keys(): + expected_delay = delay_lookup[equipment_name] + + with monkeypatch.context() as ctx: + ctx.setattr(BehaviorOphysDataTransforms, + '__init__', + xform_init) + + ctx.setattr(BehaviorOphysDataTransforms, + 'get_metadata', + dummy_get_metadata) + + ctx.setattr(OphysTimeAligner, + '__init__', + aligner_init) + + ctx.setattr(OphysTimeAligner, + '_get_clipped_stim_timestamps', + dummy_clipped) + + ctx.setattr(OphysTimeAligner, + '_get_monitor_delay', + dummy_delay) + + xforms = BehaviorOphysDataTransforms() + with pytest.warns(UserWarning): +> m = xforms.get_monitor_delay() + +test_behavior_ophys_data_xforms.py:485: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ +../../../brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py:207: in get_monitor_delay + self._load_stimulus_timestamps_and_delay() +../../../brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py:165: in _load_stimulus_timestamps_and_delay + equipment_name = self.get_metadata().equipment_name +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce9b22c810> + + @property + def equipment_name(self) -> str: +> return self._equipment_name.value +E AttributeError: 'BehaviorMetadata' object has no attribute '_equipment_name' + +../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:290: AttributeError/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:22: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:22: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:43: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:62: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:144: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:159: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:159: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:170: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:170: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:223: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:246: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightlydef test_behavior_ophys_experiment_list_data_attributes_and_methods(): + # Test that data related methods/attributes/properties for + # BehaviorOphysExperiment are returned properly. + + # This test will need to be updated if: + # 1. Data being returned by class has changed + # 2. Inheritance of class has changed + expected = { + 'average_projection', + 'behavior_session_id', + 'cell_specimen_table', + 'corrected_fluorescence_traces', + 'dff_traces', + 'events', + 'eye_tracking', + 'eye_tracking_rig_geometry', + 'get_cell_specimen_ids', + 'get_cell_specimen_indices', + 'get_dff_traces', + 'get_performance_metrics', + 'get_reward_rate', + 'get_rolling_performance_df', + 'get_segmentation_mask_image', + 'licks', + 'max_projection', + 'metadata', + 'motion_correction', + 'ophys_experiment_id', + 'ophys_session_id', + 'ophys_timestamps', + 'raw_running_speed', + 'rewards', + 'roi_masks', + 'running_speed', + 'segmentation_mask_image', + 'stimulus_presentations', + 'stimulus_templates', + 'stimulus_timestamps', + 'task_parameters', + 'trials' + } + + behavior_ophys_experiment = BehaviorOphysExperiment(api=MagicMock()) + obt = behavior_ophys_experiment.list_data_attributes_and_methods() + +> assert any(expected ^ set(obt)) is False +E AssertionError: assert True is False +E + where True = any(({'average_projection', 'behavior_session_id', 'cell_specimen_table', 'corrected_fluorescence_traces', 'dff_traces', 'events', ...} ^ {'average_projection', 'behavior_session_id', 'cell_specimen_table', 'corrected_fluorescence_traces', 'dff_traces', 'events', ...})) +E + where {'average_projection', 'behavior_session_id', 'cell_specimen_table', 'corrected_fluorescence_traces', 'dff_traces', 'events', ...} = set(['average_projection', 'behavior_session_id', 'cell_specimen_table', 'corrected_fluorescence_traces', 'dff_traces', 'events', ...]) + +test_behavior_ophys_experiment.py:300: AssertionError/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_lims_api.py:27: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_lims_api.py:36: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_lims_api.py:36: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_lims_api.py:59: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_lims_api.py:82: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_lims_api.py:447: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightlydef test_behavior_session_list_data_attributes_and_methods(): + # Test that data related methods/attributes/properties for + # BehaviorSession are returned properly. + + # This test will need to be updated if: + # 1. Data being returned by class has changed + # 2. Inheritance of class has changed + expected = { + 'behavior_session_id', + 'get_performance_metrics', + 'get_reward_rate', + 'get_rolling_performance_df', + 'licks', + 'metadata', + 'raw_running_speed', + 'rewards', + 'running_speed', + 'stimulus_presentations', + 'stimulus_templates', + 'stimulus_timestamps', + 'task_parameters', + 'trials' + } + + behavior_session = BehaviorSession(api=MagicMock()) + obt = behavior_session.list_data_attributes_and_methods() + +> assert any(expected ^ set(obt)) is False +E AssertionError: assert True is False +E + where True = any(({'behavior_session_id', 'get_performance_metrics', 'get_reward_rate', 'get_rolling_performance_df', 'licks', 'metadata', ...} ^ {'behavior_session_id', 'from_internal_mixed', 'from_nwb', 'get_performance_metrics', 'get_reward_rate', 'get_rolling_performance_df', ...})) +E + where {'behavior_session_id', 'from_internal_mixed', 'from_nwb', 'get_performance_metrics', 'get_reward_rate', 'get_rolling_performance_df', ...} = set(['behavior_session_id', 'from_internal_mixed', 'from_nwb', 'get_performance_metrics', 'get_reward_rate', 'get_rolling_performance_df', ...]) + +test_behavior_session.py:99: AssertionError/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:64: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:64: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:76: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:76: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:88: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:88: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:100: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:100: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:112: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:112: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:124: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:124: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:136: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:136: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:148: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:148: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:160: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:160: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:172: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:172: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:184: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:184: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:196: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:196: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:208: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:208: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:220: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:220: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:241: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:250: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:250: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:268: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:268: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:286: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:286: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:21: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:28: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:42: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:49: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:58: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:58: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:58: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:70: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:70: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:70: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:82: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:90: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:96: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:103: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:113: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:123: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:129: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:135: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:141: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_trials_processing.py:11: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_trials_processing.py:11: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightlynwbfile = root pynwb.file.NWBFile at 0x140525322581840 +Fields: + acquisition: { + v_in <class 'pynwb.base.TimeSeries'>, + v_...n + session_start_time: 2021-06-04 07:15:24.143189-07:00 + timestamps_reference_time: 2021-06-04 07:15:24.143189-07:00 + +roundtrip = True, roundtripper = <function roundtripper.<locals>.f at 0x7fce8e1ed950> +running_acquisition_df_fixture = dx v_sig v_in +timestamps +1.0 1 1 1 +2.0 1 1 1 +3.0 1 1 1 + + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_add_running_acquisition_to_nwbfile(nwbfile, roundtrip, roundtripper, + running_acquisition_df_fixture): + nwbfile = nwb.add_running_acquisition_to_nwbfile( + nwbfile, running_acquisition_df_fixture) + + if roundtrip: + obt = roundtripper(nwbfile, BehaviorNwbApi) + else: + obt = BehaviorNwbApi.from_nwbfile(nwbfile) + +> obt_running_acq_df = obt.get_running_acquisition_df() + +test_write_behavior_nwb.py:38: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.session_apis.data_io.behavior_nwb_api.BehaviorNwbApi object at 0x7fce9b326140> + + def get_running_acquisition_df(self): +> raise NotImplementedError() +E NotImplementedError + +../../../brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py:121: NotImplementedErrornwbfile = root pynwb.file.NWBFile at 0x140525180967888 +Fields: + acquisition: { + v_in <class 'pynwb.base.TimeSeries'>, + v_...n + session_start_time: 2021-06-04 07:15:24.611157-07:00 + timestamps_reference_time: 2021-06-04 07:15:24.611157-07:00 + +roundtrip = False, roundtripper = <function roundtripper.<locals>.f at 0x7fce92606440> +running_acquisition_df_fixture = dx v_sig v_in +timestamps +1.0 1 1 1 +2.0 1 1 1 +3.0 1 1 1 + + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_add_running_acquisition_to_nwbfile(nwbfile, roundtrip, roundtripper, + running_acquisition_df_fixture): + nwbfile = nwb.add_running_acquisition_to_nwbfile( + nwbfile, running_acquisition_df_fixture) + + if roundtrip: + obt = roundtripper(nwbfile, BehaviorNwbApi) + else: + obt = BehaviorNwbApi.from_nwbfile(nwbfile) + +> obt_running_acq_df = obt.get_running_acquisition_df() + +test_write_behavior_nwb.py:38: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.session_apis.data_io.behavior_nwb_api.BehaviorNwbApi object at 0x7fce92602cd0> + + def get_running_acquisition_df(self): +> raise NotImplementedError() +E NotImplementedError + +../../../brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py:121: NotImplementedErrornwbfile = root pynwb.file.NWBFile at 0x140525180557392 +Fields: + file_create_date: [datetime.datetime(2021, 6, 4, 7, 15, 24, 622...n + session_start_time: 2021-06-04 07:15:24.621814-07:00 + timestamps_reference_time: 2021-06-04 07:15:24.621814-07:00 + +running_speed = RunningSpeed(timestamps=[1.0, 2.0, 3.0], values=[4, 5, 6]), roundtrip = True, roundtripper = <function roundtripper.<locals>.f at 0x7fce926065f0> + + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_add_running_speed_to_nwbfile(nwbfile, running_speed, + roundtrip, roundtripper): + + nwbfile = nwb.add_running_speed_to_nwbfile(nwbfile, running_speed) + + if roundtrip: + obt = roundtripper(nwbfile, BehaviorNwbApi) + else: + obt = BehaviorNwbApi.from_nwbfile(nwbfile) + +> obt_running_speed = obt.get_running_speed() + +test_write_behavior_nwb.py:56: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.session_apis.data_io.behavior_nwb_api.BehaviorNwbApi object at 0x7fce925f48c0> + + def get_running_speed(self): +> raise NotImplementedError() +E NotImplementedError + +../../../brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py:124: NotImplementedErrornwbfile = root pynwb.file.NWBFile at 0x140525180835984 +Fields: + file_create_date: [datetime.datetime(2021, 6, 4, 7, 15, 25, 126...n + session_start_time: 2021-06-04 07:15:25.126058-07:00 + timestamps_reference_time: 2021-06-04 07:15:25.126058-07:00 + +running_speed = RunningSpeed(timestamps=[1.0, 2.0, 3.0], values=[4, 5, 6]), roundtrip = False, roundtripper = <function roundtripper.<locals>.f at 0x7fce8e1edb90> + + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_add_running_speed_to_nwbfile(nwbfile, running_speed, + roundtrip, roundtripper): + + nwbfile = nwb.add_running_speed_to_nwbfile(nwbfile, running_speed) + + if roundtrip: + obt = roundtripper(nwbfile, BehaviorNwbApi) + else: + obt = BehaviorNwbApi.from_nwbfile(nwbfile) + +> obt_running_speed = obt.get_running_speed() + +test_write_behavior_nwb.py:56: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <allensdk.brain_observatory.behavior.session_apis.data_io.behavior_nwb_api.BehaviorNwbApi object at 0x7fce922053c0> + + def get_running_speed(self): +> raise NotImplementedError() +E NotImplementedError + +../../../brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py:124: NotImplementedError \ No newline at end of file diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py b/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py index 8ea3e45ab..d03431820 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py @@ -8,7 +8,8 @@ import pytz from allensdk import OneResultExpectedError -from allensdk.brain_observatory.behavior.metadata.behavior_metadata import \ +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ BehaviorMetadata from allensdk.brain_observatory.behavior.mtrain import ExtendedTrialSchema from allensdk.brain_observatory.behavior.session_apis.data_io import ( diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py b/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py index 59c5b841e..e1ca6e79e 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py @@ -6,7 +6,8 @@ import pandas as pd import pytz -from allensdk.brain_observatory.behavior.metadata.behavior_metadata import ( +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import ( description_dict, get_task_parameters, get_expt_description, BehaviorMetadata) diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py index 53713bf19..798c20bb0 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py @@ -3,7 +3,8 @@ import numpy as np import pandas as pd -from allensdk.brain_observatory.behavior.metadata.behavior_metadata import \ +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ BehaviorMetadata from allensdk.brain_observatory.behavior.session_apis.data_transforms import BehaviorOphysDataTransforms # noqa: E501 from allensdk.internal.brain_observatory.time_sync import OphysTimeAligner From 85594d11748a183cbae7a236e9a42be62ce196ec Mon Sep 17 00:00:00 2001 From: aamster Date: Fri, 4 Jun 2021 12:45:41 -0700 Subject: [PATCH 018/234] make stimulus_file a typed object in test --- .../behavior/test_behavior_lims_api.py | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py b/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py index d03431820..77a3891cb 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py @@ -1,4 +1,6 @@ import math +import pickle +import tempfile from datetime import datetime from uuid import UUID @@ -8,9 +10,16 @@ import pytz from allensdk import OneResultExpectedError +from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_metadata import \ BehaviorMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_session_uuid import \ + BehaviorSessionUUID +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.date_of_acquisition import \ + DateOfAcquisition from allensdk.brain_observatory.behavior.mtrain import ExtendedTrialSchema from allensdk.brain_observatory.behavior.session_apis.data_io import ( BehaviorLimsApi, BehaviorLimsExtractor, BehaviorOphysLimsApi) @@ -152,7 +161,12 @@ def _behavior_stimulus_file(self): "session_uuid": '138531ab-fe59-4523-9154-07c8d97bbe03', "start_time": datetime(2019, 9, 26, 9), } - return data + with tempfile.NamedTemporaryFile('wb') as f: + pickle.dump(data, f) + f.seek(0) + file = StimulusFile.from_json( + dict_repr={'behavior_stimulus_file': f.name}) + return file def get_running_acquisition_df(self, lowpass=True): return pd.DataFrame( @@ -224,12 +238,11 @@ def dummy_init(self, extractor, behavior_stimulus_file): '__init__', dummy_init) stimulus_file = MockBehaviorLimsApi._behavior_stimulus_file() - metadata = BehaviorMetadata( - extractor=MockBehaviorLimsApi.extractor, - behavior_stimulus_file=stimulus_file) + uuid = BehaviorSessionUUID.from_stimulus_file( + stimulus_file=stimulus_file) expected = UUID('138531ab-fe59-4523-9154-07c8d97bbe03') - assert expected == metadata.behavior_session_uuid + assert expected == uuid.value def test_get_stimulus_frame_rate(MockBehaviorLimsApi): @@ -237,13 +250,6 @@ def test_get_stimulus_frame_rate(MockBehaviorLimsApi): assert 62.0 == api.get_stimulus_frame_rate() -def test_get_date_of_acquisition(MockBehaviorLimsApi): - api = MockBehaviorLimsApi - expected = datetime(2019, 9, 26, 16, tzinfo=pytz.UTC) - actual = api.get_metadata().date_of_acquisition - assert expected == actual - - def test_get_running_speed(MockBehaviorLimsApi): expected = pd.DataFrame({ "timestamps": [0.0, 0.1, 0.2], From 8f5e08becf4a874d3143d5f8c9e17ac182785e3a Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 7 Jun 2021 06:48:53 -0700 Subject: [PATCH 019/234] adds to_nwb --- .../data_objects/_base/_data_object_abc.py | 18 -------- .../_base/writable_mixins/__init__.py | 0 .../writable_mixins/nwb_writable_mixin.py | 27 +++++++++++ .../metadata/behavior_metadata/age.py | 9 ++-- .../behavior_metadata/behavior_metadata.py | 46 ++++++++++++++++++- 5 files changed, 77 insertions(+), 23 deletions(-) create mode 100644 allensdk/brain_observatory/behavior/data_objects/_base/writable_mixins/__init__.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/_base/writable_mixins/nwb_writable_mixin.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py index 0a9065994..887a7a151 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py @@ -53,21 +53,3 @@ def from_nwb(cls, nwbfile: NWBFile) -> "DataObject": # pragma: no cover An instantiated DataObject which has `name` and `value` properties """ raise NotImplementedError() - - @abc.abstractmethod - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: # pragma: no cover - """Given an already populated DataObject, return an pyNWB file object - that had had DataObject data added. - - Parameters - ---------- - nwbfile : NWBFile - An NWB file object - - Returns - ------- - NWBFile - An NWB file object that has had data from the DataObject added - to it. - """ - raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/writable_mixins/__init__.py b/allensdk/brain_observatory/behavior/data_objects/_base/writable_mixins/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/writable_mixins/nwb_writable_mixin.py b/allensdk/brain_observatory/behavior/data_objects/_base/writable_mixins/nwb_writable_mixin.py new file mode 100644 index 000000000..1070dca21 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/_base/writable_mixins/nwb_writable_mixin.py @@ -0,0 +1,27 @@ +import abc + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject + + +class NwbWritableMixin: + """Marks a data object as writable to NWB""" + @classmethod + @abc.abstractmethod + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: # pragma: no cover + """Given an already populated DataObject, return an pyNWB file object + that had had DataObject data added. + + Parameters + ---------- + nwbfile : NWBFile + An NWB file object + + Returns + ------- + NWBFile + An NWB file object that has had data from the DataObject added + to it. + """ + raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py index bc8273513..9ea1e2b08 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py @@ -37,11 +37,14 @@ def from_lims(cls, behavior_session_id: int, return cls(age=age) @classmethod - def from_nwb(cls, nwbfile: NWBFile) -> "EquipmentName": + def from_nwb(cls, nwbfile: NWBFile) -> "Age": pass - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass + @staticmethod + def to_iso8601(age: int): + if age is None: + return 'null' + return f'P{age}D' @staticmethod def _age_code_to_days(age: str, warn=False) -> Optional[int]: diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index d5c63c622..f22efd5e6 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -13,6 +13,9 @@ .internal_mixed_readable_mixin \ import \ InternalMixedReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.writable_mixins\ + .nwb_writable_mixin import \ + NwbWritableMixin from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.age import \ Age @@ -49,6 +52,9 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.stimulus_frame_rate import \ StimulusFrameRate +from allensdk.brain_observatory.behavior.schemas import SubjectMetadataSchema, \ + CompleteOphysBehaviorMetadataSchema, BehaviorMetadataSchema +from allensdk.brain_observatory.nwb import load_pynwb_extension from allensdk.brain_observatory.session_api_utils import compare_session_fields from allensdk.internal.api import PostgresQueryMixin @@ -191,7 +197,8 @@ def get_task_parameters(data: Dict) -> Dict: return task_parameters -class BehaviorMetadata(DataObject, InternalMixedReadableMixin): +class BehaviorMetadata(DataObject, InternalMixedReadableMixin, + NwbWritableMixin): """Container class for behavior metadata""" def __init__(self, behavior_session_id: BehaviorSessionId, @@ -350,7 +357,42 @@ def to_json(self) -> dict: pass def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass + BehaviorSubject = load_pynwb_extension(SubjectMetadataSchema, + 'ndx-aibs-behavior-ophys') + nwb_subject = BehaviorSubject( + description="A visual behavior subject with a LabTracks ID", + age=Age.to_iso8601(age=self.age_in_days), + driver_line=self.driver_line, + genotype=self.full_genotype, + subject_id=str(self.mouse_id), + reporter_line=self.reporter_line, + sex=self.sex, + species='Mus musculus') + nwbfile.subject = nwb_subject + + nwb_metadata = self._to_nwb() + extension = self._get_nwb_extension() + nwb_metadata = extension(**nwb_metadata) + nwbfile.add_lab_meta_data(nwb_metadata) + + return nwbfile + + @abc.abstractmethod + def _to_nwb(self) -> dict: + """Constructs data structure for non-subject metadata""" + return dict( + name='metadata', + behavior_session_id=self.behavior_session_id, + behavior_session_uuid=str(self.behavior_session_uuid), + stimulus_frame_rate=self.stimulus_frame_rate, + session_type=self.session_type, + equipment_name=self.equipment_name + ) + + @staticmethod + def _get_nwb_extension(): + return load_pynwb_extension(BehaviorMetadataSchema, + 'ndx-aibs-behavior-ophys') def _get_properties(self, vars_: dict): """Returns all property names and values""" From 69cd51de81939eaa2a121b9c3d9a66cffbef0291 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 7 Jun 2021 07:43:54 -0700 Subject: [PATCH 020/234] adds from_nwb --- .../metadata/behavior_metadata/age.py | 3 +- .../behavior_metadata/behavior_metadata.py | 31 +++++++++++++++++-- .../behavior_metadata/behavior_session_id.py | 13 ++------ .../behavior_session_uuid.py | 7 ++--- .../behavior_metadata/date_of_acquisition.py | 5 +-- .../metadata/behavior_metadata/driver_line.py | 6 ++-- .../behavior_metadata/equipment_name.py | 6 ++-- .../behavior_metadata/full_genotype.py | 9 +----- .../metadata/behavior_metadata/mouse_id.py | 7 ++--- .../behavior_metadata/reporter_line.py | 2 +- .../behavior_metadata/session_type.py | 6 ++-- .../metadata/behavior_metadata/sex.py | 7 ++--- .../behavior_metadata/stimulus_frame_rate.py | 6 ++-- 13 files changed, 51 insertions(+), 57 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py index 9ea1e2b08..8c0849d59 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py @@ -38,7 +38,8 @@ def from_lims(cls, behavior_session_id: int, @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "Age": - pass + age = cls._age_code_to_days(age=nwbfile.subject.age) + return cls(age=age) @staticmethod def to_iso8601(age: int): diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index f22efd5e6..cfcef6b2e 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -53,7 +53,8 @@ .behavior_metadata.stimulus_frame_rate import \ StimulusFrameRate from allensdk.brain_observatory.behavior.schemas import SubjectMetadataSchema, \ - CompleteOphysBehaviorMetadataSchema, BehaviorMetadataSchema + CompleteOphysBehaviorMetadataSchema, BehaviorMetadataSchema, \ + OphysBehaviorMetadataSchema from allensdk.brain_observatory.nwb import load_pynwb_extension from allensdk.brain_observatory.session_api_utils import compare_session_fields from allensdk.internal.api import PostgresQueryMixin @@ -290,7 +291,33 @@ def from_json(cls, dict_repr: dict) -> "BehaviorMetadata": @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorMetadata": - pass + behavior_session_id = BehaviorSessionId.from_nwb(nwbfile=nwbfile) + equipment_name = EquipmentName.from_nwb(nwbfile=nwbfile) + mouse_id = MouseId.from_nwb(nwbfile=nwbfile) + sex = Sex.from_nwb(nwbfile=nwbfile) + age = Age.from_nwb(nwbfile=nwbfile) + stimulus_frame_rate = StimulusFrameRate.from_nwb(nwbfile=nwbfile) + session_type = SessionType.from_nwb(nwbfile=nwbfile) + reporter_line = ReporterLine.from_nwb(nwbfile=nwbfile) + driver_line = DriverLine.from_nwb(nwbfile=nwbfile) + genotype = FullGenotype.from_nwb(nwbfile=nwbfile) + date_of_acquisition = DateOfAcquisition.from_nwb(nwbfile=nwbfile) + session_uuid = BehaviorSessionUUID.from_nwb(nwbfile=nwbfile) + + return cls( + behavior_session_id=behavior_session_id, + equipment_name=equipment_name, + sex=sex, + age=age, + stimulus_frame_rate=stimulus_frame_rate, + session_type=session_type, + date_of_acquisition=date_of_acquisition, + reporter_line=reporter_line, + full_genotype=genotype, + behavior_session_uuid=session_uuid, + driver_line=driver_line, + mouse_id=mouse_id + ) @property def equipment_name(self) -> str: diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py index 513b25fdd..7a8b6e58a 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py @@ -44,14 +44,5 @@ def from_lims( @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorSessionId": - # TODO: - # This implementation will be wrong when trying to get - # behavior session id for an ophys experiment. - # Will need to revisit. - return cls(behavior_session_id=int(nwbfile.identifier)) - - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - # TODO: - # Likely need to have some yet to be determined interaction with - # the out-of-scope `metadata` DataObject - raise NotImplementedError + metadata = nwbfile.lab_meta_data['metadata'] + return cls(behavior_session_id=metadata.behavior_session_id) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py index 0a3a38bd3..b1c8c1038 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py @@ -32,10 +32,9 @@ def from_stimulus_file( @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorSessionUUID": - pass - - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass + metadata = nwbfile.lab_meta_data['metadata'] + id = uuid.UUID(metadata.behavior_session_uuid) + return cls(behavior_session_uuid=id) def validate(self, behavior_session_id: int, foraging_id: int, diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py index 0268124de..41326520f 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py @@ -36,10 +36,7 @@ def from_lims( @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "DateOfAcquisition": - pass - - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass + return cls(date_of_acquisition=nwbfile.session_start_time) def validate(self, stimulus_file: StimulusFile, behavior_session_id: int) -> "DateOfAcquisition": diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/driver_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/driver_line.py index acad1c32a..0f9b3c509 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/driver_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/driver_line.py @@ -45,7 +45,5 @@ def from_lims(cls, behavior_session_id: int, @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "DriverLine": - pass - - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass \ No newline at end of file + driver_line = sorted(list(nwbfile.subject.driver_line)) + return cls(driver_line=driver_line) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py index d6e54c61d..b3d92464c 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py @@ -30,7 +30,5 @@ def from_lims(cls, behavior_session_id: int, @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "EquipmentName": - pass - - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass \ No newline at end of file + metadata = nwbfile.lab_meta_data['metadata'] + return cls(equipment_name=metadata.equipment_name) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/full_genotype.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/full_genotype.py index ba966ea32..bd288ef49 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/full_genotype.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/full_genotype.py @@ -22,10 +22,6 @@ def from_json(cls, dict_repr: dict) -> "FullGenotype": def to_json(self) -> dict: return {"sex": self.value} - @classmethod - def from_string(cls, full_genotype: str): - return cls(full_genotype=full_genotype) - @classmethod def from_lims(cls, behavior_session_id: int, lims_db: PostgresQueryMixin) -> "FullGenotype": @@ -40,10 +36,7 @@ def from_lims(cls, behavior_session_id: int, @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "FullGenotype": - pass - - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass + return cls(full_genotype=nwbfile.subject.genotype) def parse_cre_line(self, warn=False) -> Optional[str]: """ diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/mouse_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/mouse_id.py index 46f3f764e..59e4fbc4b 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/mouse_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/mouse_id.py @@ -38,8 +38,5 @@ def from_lims(cls, behavior_session_id: int, return cls(mouse_id=mouse_id) @classmethod - def from_nwb(cls, nwbfile: NWBFile) -> "EquipmentName": - pass - - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass \ No newline at end of file + def from_nwb(cls, nwbfile: NWBFile) -> "MouseId": + return cls(mouse_id=int(nwbfile.subject.subject_id)) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/reporter_line.py index 69aaed088..d528ac797 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/reporter_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/reporter_line.py @@ -46,7 +46,7 @@ def from_lims(cls, behavior_session_id: int, @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "ReporterLine": - pass + return cls(reporter_line=nwbfile.subject.reporter_line) def to_nwb(self, nwbfile: NWBFile) -> NWBFile: pass diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py index 68a4323c6..19876160b 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py @@ -43,7 +43,5 @@ def from_stimulus_file( @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "SessionType": - pass - - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass + metadata = nwbfile.lab_meta_data['metadata'] + return cls(session_type=metadata.session_type) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/sex.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/sex.py index c52a2a80a..252880172 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/sex.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/sex.py @@ -33,8 +33,5 @@ def from_lims(cls, behavior_session_id: int, return cls(sex=sex) @classmethod - def from_nwb(cls, nwbfile: NWBFile) -> "EquipmentName": - pass - - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass \ No newline at end of file + def from_nwb(cls, nwbfile: NWBFile) -> "Sex": + return cls(sex=nwbfile.subject.sex) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py index 9c60e8a2f..d2b0b25cc 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py @@ -25,7 +25,5 @@ def from_stimulus_file( @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "StimulusFrameRate": - pass - - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass \ No newline at end of file + metadata = nwbfile.lab_meta_data['metadata'] + return cls(stimulus_frame_rate=metadata.stimulus_frame_rate) From 214aae0f31351f002a9597105375c80e95a82748 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 7 Jun 2021 08:52:46 -0700 Subject: [PATCH 021/234] separate subject metadata from behavior metadata --- .../behavior_metadata/behavior_metadata.py | 136 ++-------------- .../metadata/subject_metadata/__init__.py | 0 .../age.py | 0 .../driver_line.py | 0 .../full_genotype.py | 0 .../mouse_id.py | 0 .../reporter_line.py | 0 .../sex.py | 0 .../subject_metadata/subject_metadata.py | 147 ++++++++++++++++++ 9 files changed, 156 insertions(+), 127 deletions(-) create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/__init__.py rename allensdk/brain_observatory/behavior/data_objects/metadata/{behavior_metadata => subject_metadata}/age.py (100%) rename allensdk/brain_observatory/behavior/data_objects/metadata/{behavior_metadata => subject_metadata}/driver_line.py (100%) rename allensdk/brain_observatory/behavior/data_objects/metadata/{behavior_metadata => subject_metadata}/full_genotype.py (100%) rename allensdk/brain_observatory/behavior/data_objects/metadata/{behavior_metadata => subject_metadata}/mouse_id.py (100%) rename allensdk/brain_observatory/behavior/data_objects/metadata/{behavior_metadata => subject_metadata}/reporter_line.py (100%) rename allensdk/brain_observatory/behavior/data_objects/metadata/{behavior_metadata => subject_metadata}/sex.py (100%) create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index cfcef6b2e..6a32a8e45 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -1,7 +1,6 @@ -import abc import uuid from datetime import datetime -from typing import Dict, List, Optional +from typing import Dict, Optional import re import numpy as np from pynwb import NWBFile @@ -16,45 +15,26 @@ from allensdk.brain_observatory.behavior.data_objects._base.writable_mixins\ .nwb_writable_mixin import \ NwbWritableMixin -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.age import \ - Age from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_session_uuid import \ BehaviorSessionUUID from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.date_of_acquisition import \ DateOfAcquisition -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.driver_line import \ - DriverLine from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.equipment_name import \ EquipmentName from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.foraging_id import \ ForagingId -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.full_genotype import \ - FullGenotype -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.mouse_id import \ - MouseId -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.reporter_line import \ - ReporterLine from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.session_type import \ SessionType -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.sex import \ - Sex from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.stimulus_frame_rate import \ StimulusFrameRate from allensdk.brain_observatory.behavior.schemas import SubjectMetadataSchema, \ - CompleteOphysBehaviorMetadataSchema, BehaviorMetadataSchema, \ - OphysBehaviorMetadataSchema + BehaviorMetadataSchema from allensdk.brain_observatory.nwb import load_pynwb_extension from allensdk.brain_observatory.session_api_utils import compare_session_fields from allensdk.internal.api import PostgresQueryMixin @@ -204,29 +184,17 @@ class BehaviorMetadata(DataObject, InternalMixedReadableMixin, def __init__(self, behavior_session_id: BehaviorSessionId, equipment_name: EquipmentName, - sex: Sex, - age: Age, stimulus_frame_rate: StimulusFrameRate, session_type: SessionType, date_of_acquisition: DateOfAcquisition, - reporter_line: ReporterLine, - full_genotype: FullGenotype, - behavior_session_uuid: BehaviorSessionUUID, - driver_line: DriverLine, - mouse_id: MouseId): + behavior_session_uuid: BehaviorSessionUUID): super().__init__(name='behavior_metadata', value=self) self._behavior_session_id = behavior_session_id self._equipment_name = equipment_name - self._sex = sex - self._age = age self._stimulus_frame_rate = stimulus_frame_rate self._session_type = session_type self._date_of_acquisition = date_of_acquisition - self._reporter_line = reporter_line - self._full_genotype = full_genotype self._behavior_session_uuid = behavior_session_uuid - self._driver_line = driver_line - self._mouse_id = mouse_id self._exclude_from_equals = set() @@ -240,10 +208,6 @@ def from_internal_mixed( ) -> "BehaviorMetadata": equipment_name = EquipmentName.from_lims( behavior_session_id=behavior_session_id.value, lims_db=lims_db) - sex = Sex.from_lims(behavior_session_id=behavior_session_id.value, - lims_db=lims_db) - age = Age.from_lims(behavior_session_id=behavior_session_id.value, - lims_db=lims_db) stimulus_frame_rate = StimulusFrameRate.from_stimulus_file( stimulus_timestamps=stimulus_timestamps) session_type = SessionType.from_stimulus_file( @@ -252,10 +216,6 @@ def from_internal_mixed( behavior_session_id=behavior_session_id.value, lims_db=lims_db)\ .validate(stimulus_file=stimulus_file, behavior_session_id=behavior_session_id.value) - reporter_line = ReporterLine.from_lims( - behavior_session_id=behavior_session_id.value, lims_db=lims_db) - full_genotype = FullGenotype.from_lims( - behavior_session_id=behavior_session_id.value, lims_db=lims_db) foraging_id = ForagingId.from_lims( behavior_session_id=behavior_session_id.value, lims_db=lims_db) @@ -264,25 +224,14 @@ def from_internal_mixed( .validate(behavior_session_id=behavior_session_id.value, foraging_id=foraging_id.value, stimulus_file=stimulus_file) - driver_line = DriverLine.from_lims( - behavior_session_id=behavior_session_id.value, lims_db=lims_db) - mouse_id = MouseId.from_lims( - behavior_session_id=behavior_session_id.value, - lims_db=lims_db) return cls( behavior_session_id=behavior_session_id, equipment_name=equipment_name, - sex=sex, - age=age, stimulus_frame_rate=stimulus_frame_rate, session_type=session_type, date_of_acquisition=date_of_acquisition, - reporter_line=reporter_line, - full_genotype=full_genotype, behavior_session_uuid=behavior_session_uuid, - driver_line=driver_line, - mouse_id=mouse_id ) @classmethod @@ -293,44 +242,24 @@ def from_json(cls, dict_repr: dict) -> "BehaviorMetadata": def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorMetadata": behavior_session_id = BehaviorSessionId.from_nwb(nwbfile=nwbfile) equipment_name = EquipmentName.from_nwb(nwbfile=nwbfile) - mouse_id = MouseId.from_nwb(nwbfile=nwbfile) - sex = Sex.from_nwb(nwbfile=nwbfile) - age = Age.from_nwb(nwbfile=nwbfile) stimulus_frame_rate = StimulusFrameRate.from_nwb(nwbfile=nwbfile) session_type = SessionType.from_nwb(nwbfile=nwbfile) - reporter_line = ReporterLine.from_nwb(nwbfile=nwbfile) - driver_line = DriverLine.from_nwb(nwbfile=nwbfile) - genotype = FullGenotype.from_nwb(nwbfile=nwbfile) date_of_acquisition = DateOfAcquisition.from_nwb(nwbfile=nwbfile) session_uuid = BehaviorSessionUUID.from_nwb(nwbfile=nwbfile) return cls( behavior_session_id=behavior_session_id, equipment_name=equipment_name, - sex=sex, - age=age, stimulus_frame_rate=stimulus_frame_rate, session_type=session_type, date_of_acquisition=date_of_acquisition, - reporter_line=reporter_line, - full_genotype=genotype, - behavior_session_uuid=session_uuid, - driver_line=driver_line, - mouse_id=mouse_id + behavior_session_uuid=session_uuid ) @property def equipment_name(self) -> str: return self._equipment_name.value - @property - def sex(self) -> str: - return self._sex.value - - @property - def age_in_days(self) -> Optional[int]: - return self._age.value - @property def stimulus_frame_rate(self) -> float: return self._stimulus_frame_rate.value @@ -343,34 +272,10 @@ def session_type(self) -> str: def date_of_acquisition(self) -> datetime: return self._date_of_acquisition.value - @property - def reporter_line(self) -> Optional[str]: - return self._reporter_line.value - - @property - def indicator(self) -> Optional[str]: - return self._reporter_line.indicator - - @property - def full_genotype(self) -> str: - return self._full_genotype.value - - @property - def cre_line(self) -> Optional[str]: - return self._full_genotype.parse_cre_line(warn=True) - @property def behavior_session_uuid(self) -> Optional[uuid.UUID]: return self._behavior_session_uuid.value - @property - def driver_line(self) -> List[str]: - return self._driver_line.value - - @property - def mouse_id(self) -> int: - return self._mouse_id.value - @property def behavior_session_id(self) -> int: return self._behavior_session_id.value @@ -384,30 +289,9 @@ def to_json(self) -> dict: pass def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - BehaviorSubject = load_pynwb_extension(SubjectMetadataSchema, - 'ndx-aibs-behavior-ophys') - nwb_subject = BehaviorSubject( - description="A visual behavior subject with a LabTracks ID", - age=Age.to_iso8601(age=self.age_in_days), - driver_line=self.driver_line, - genotype=self.full_genotype, - subject_id=str(self.mouse_id), - reporter_line=self.reporter_line, - sex=self.sex, - species='Mus musculus') - nwbfile.subject = nwb_subject - - nwb_metadata = self._to_nwb() - extension = self._get_nwb_extension() - nwb_metadata = extension(**nwb_metadata) - nwbfile.add_lab_meta_data(nwb_metadata) - - return nwbfile - - @abc.abstractmethod - def _to_nwb(self) -> dict: - """Constructs data structure for non-subject metadata""" - return dict( + extension = load_pynwb_extension(BehaviorMetadataSchema, + 'ndx-aibs-behavior-ophys') + nwb_metadata = extension( name='metadata', behavior_session_id=self.behavior_session_id, behavior_session_uuid=str(self.behavior_session_uuid), @@ -415,11 +299,9 @@ def _to_nwb(self) -> dict: session_type=self.session_type, equipment_name=self.equipment_name ) + nwbfile.add_lab_meta_data(nwb_metadata) - @staticmethod - def _get_nwb_extension(): - return load_pynwb_extension(BehaviorMetadataSchema, - 'ndx-aibs-behavior-ophys') + return nwbfile def _get_properties(self, vars_: dict): """Returns all property names and values""" diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/__init__.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/age.py rename to allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/driver_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/driver_line.py rename to allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/full_genotype.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/full_genotype.py rename to allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/mouse_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/mouse_id.py rename to allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/reporter_line.py rename to allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/sex.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/sex.py rename to allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py new file mode 100644 index 000000000..d58948755 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py @@ -0,0 +1,147 @@ +from typing import Optional, List + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject, \ + BehaviorSessionId +from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ + .lims_readable_mixin import \ + LimsReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.writable_mixins\ + .nwb_writable_mixin import \ + NwbWritableMixin +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.age import \ + Age +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.driver_line import \ + DriverLine +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.full_genotype import \ + FullGenotype +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.mouse_id import \ + MouseId +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.reporter_line import \ + ReporterLine +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.sex import \ + Sex +from allensdk.brain_observatory.behavior.schemas import SubjectMetadataSchema +from allensdk.brain_observatory.nwb import load_pynwb_extension +from allensdk.internal.api import PostgresQueryMixin + + +class SubjectMetadata(DataObject, LimsReadableMixin, + NwbWritableMixin): + """Subject metadata""" + def __init__(self, + sex: Sex, + age: Age, + reporter_line: ReporterLine, + full_genotype: FullGenotype, + driver_line: DriverLine, + mouse_id: MouseId): + super().__init__(name='subject_metadata', value=self) + self._sex = sex + self._age = age + self._reporter_line = reporter_line + self._full_genotype = full_genotype + self._driver_line = driver_line + self._mouse_id = mouse_id + + @classmethod + def from_lims(cls, + behavior_session_id: BehaviorSessionId, + lims_db: PostgresQueryMixin) -> "SubjectMetadata": + sex = Sex.from_lims(behavior_session_id=behavior_session_id.value, + lims_db=lims_db) + age = Age.from_lims(behavior_session_id=behavior_session_id.value, + lims_db=lims_db) + reporter_line = ReporterLine.from_lims( + behavior_session_id=behavior_session_id.value, lims_db=lims_db) + full_genotype = FullGenotype.from_lims( + behavior_session_id=behavior_session_id.value, lims_db=lims_db) + driver_line = DriverLine.from_lims( + behavior_session_id=behavior_session_id.value, lims_db=lims_db) + mouse_id = MouseId.from_lims( + behavior_session_id=behavior_session_id.value, + lims_db=lims_db) + return cls( + sex=sex, + age=age, + full_genotype=full_genotype, + driver_line=driver_line, + mouse_id=mouse_id, + reporter_line=reporter_line + ) + + def to_json(self) -> dict: + pass + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "SubjectMetadata": + mouse_id = MouseId.from_nwb(nwbfile=nwbfile) + sex = Sex.from_nwb(nwbfile=nwbfile) + age = Age.from_nwb(nwbfile=nwbfile) + reporter_line = ReporterLine.from_nwb(nwbfile=nwbfile) + driver_line = DriverLine.from_nwb(nwbfile=nwbfile) + genotype = FullGenotype.from_nwb(nwbfile=nwbfile) + + return cls( + mouse_id=mouse_id, + sex=sex, + age=age, + reporter_line=reporter_line, + driver_line=driver_line, + full_genotype=genotype + ) + + @classmethod + def to_nwb(cls, nwbfile: NWBFile) -> NWBFile: + BehaviorSubject = load_pynwb_extension(SubjectMetadataSchema, + 'ndx-aibs-behavior-ophys') + nwb_subject = BehaviorSubject( + description="A visual behavior subject with a LabTracks ID", + age=Age.to_iso8601(age=cls.age_in_days), + driver_line=cls.driver_line, + genotype=cls.full_genotype, + subject_id=str(cls.mouse_id), + reporter_line=cls.reporter_line, + sex=cls.sex, + species='Mus musculus') + nwbfile.subject = nwb_subject + return nwbfile + + @property + def sex(self) -> str: + return self._sex.value + + @property + def age_in_days(self) -> Optional[int]: + return self._age.value + + @property + def reporter_line(self) -> Optional[str]: + return self._reporter_line.value + + @property + def indicator(self) -> Optional[str]: + return self._reporter_line.indicator + + @property + def full_genotype(self) -> str: + return self._full_genotype.value + + @property + def cre_line(self) -> Optional[str]: + return self._full_genotype.parse_cre_line(warn=True) + + @property + def driver_line(self) -> List[str]: + return self._driver_line.value + + @property + def mouse_id(self) -> int: + return self._mouse_id.value \ No newline at end of file From 25c05ad382295725d97ce7dd86b726f49fe55808 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 7 Jun 2021 08:53:40 -0700 Subject: [PATCH 022/234] remove file accidentally added --- .../behavior/test-reports/test.xml | 1294 ----------------- 1 file changed, 1294 deletions(-) delete mode 100644 allensdk/test/brain_observatory/behavior/test-reports/test.xml diff --git a/allensdk/test/brain_observatory/behavior/test-reports/test.xml b/allensdk/test/brain_observatory/behavior/test-reports/test.xml deleted file mode 100644 index 5662099d8..000000000 --- a/allensdk/test/brain_observatory/behavior/test-reports/test.xml +++ /dev/null @@ -1,1294 +0,0 @@ -/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:22: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:22: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:45: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:54: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:65: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:65: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:65: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightlyMockBehaviorLimsApi = <test_behavior_lims_api.MockBehaviorLimsApi.<locals>.MockBehaviorLimsApi object at 0x7fce99c359d0>, monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99c35510> - - def test_get_behavior_session_uuid(MockBehaviorLimsApi, monkeypatch): - with monkeypatch.context() as ctx: - def dummy_init(self, extractor, behavior_stimulus_file): - self._extractor = extractor - self._behavior_stimulus_file = behavior_stimulus_file - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - stimulus_file = MockBehaviorLimsApi._behavior_stimulus_file() - metadata = BehaviorMetadata( - extractor=MockBehaviorLimsApi.extractor, - behavior_stimulus_file=stimulus_file) - - expected = UUID('138531ab-fe59-4523-9154-07c8d97bbe03') -> assert expected == metadata.behavior_session_uuid - -test_behavior_lims_api.py:232: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99c358d0> - - @property - def behavior_session_uuid(self) -> Optional[uuid.UUID]: -> return self._behavior_session_uuid.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_behavior_session_uuid' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:330: AttributeErrorMockBehaviorLimsApi = <test_behavior_lims_api.MockBehaviorLimsApi.<locals>.MockBehaviorLimsApi object at 0x7fce99bd0550> - - def test_get_date_of_acquisition(MockBehaviorLimsApi): - api = MockBehaviorLimsApi - expected = datetime(2019, 9, 26, 16, tzinfo=pytz.UTC) -> actual = api.get_metadata().date_of_acquisition - -test_behavior_lims_api.py:243: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <test_behavior_lims_api.MockBehaviorLimsApi.<locals>.MockBehaviorLimsApi object at 0x7fce99bd0550> - - def get_metadata(self) -> BehaviorMetadata: - """Return metadata about the session. - :rtype: BehaviorMetadata - """ - metadata = BehaviorMetadata( - extractor=self.extractor, - stimulus_timestamps=self.get_stimulus_timestamps(), -> behavior_stimulus_file=self._behavior_stimulus_file() - ) -E TypeError: __init__() got an unexpected keyword argument 'extractor' - -../../../brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py:351: TypeError/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:292: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:296: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:301: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:305: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:309: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:313: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:317: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:326: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:335: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:342: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:357: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:373: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:385: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:388: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:392: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:396: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:400: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:404: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:408: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py:412: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds).monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99b7c810> - - def test_cre_line(monkeypatch): - """Tests that cre_line properly parsed from driver_line""" - with monkeypatch.context() as ctx: - def dummy_init(self): - pass - - def full_genotype(self): - return 'Sst-IRES-Cre/wt;Ai148(TIT2L-GC6f-ICL-tTA2)/wt' - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - ctx.setattr(BehaviorMetadata, - 'full_genotype', - property(full_genotype)) - - metadata = BehaviorMetadata() - -> assert metadata.cre_line == 'Sst-IRES-Cre' - -test_behavior_metadata.py:346: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99b7c7d0> - - @property - def cre_line(self) -> Optional[str]: -> return self._full_genotype.parse_cre_line(warn=True) -E AttributeError: 'BehaviorMetadata' object has no attribute '_full_genotype' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:326: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99ad5290> - - def test_cre_line_bad_full_genotype(monkeypatch): - """Test that cre_line is None and no error raised""" - with monkeypatch.context() as ctx: - def dummy_init(self): - pass - - def full_genotype(self): - return 'foo' - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - ctx.setattr(BehaviorMetadata, - 'full_genotype', - property(full_genotype)) - - metadata = BehaviorMetadata() - - with pytest.warns(UserWarning) as record: -> cre_line = metadata.cre_line - -test_behavior_metadata.py:368: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99ad5390> - - @property - def cre_line(self) -> Optional[str]: -> return self._full_genotype.parse_cre_line(warn=True) -E AttributeError: 'BehaviorMetadata' object has no attribute '_full_genotype' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:326: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99b7c6d0> - - def test_reporter_line(monkeypatch): - """Test that reporter line properly parsed from list""" - - class MockExtractor: - def get_reporter_line(self): - return ['foo'] - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - -> assert metadata.reporter_line == 'foo' - -test_behavior_metadata.py:393: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99b7c150> - - @property - def reporter_line(self) -> Optional[str]: -> return self._reporter_line.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:314: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99add250> - - def test_reporter_line_str(monkeypatch): - """Test that reporter line returns itself if str""" - - class MockExtractor: - def get_reporter_line(self): - return 'foo' - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - -> assert metadata.reporter_line == 'foo' - -test_behavior_metadata.py:415: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99add510> - - @property - def reporter_line(self) -> Optional[str]: -> return self._reporter_line.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:314: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99add390>, input_reporter_line = ('foo', 'bar'), warning_msg = 'More than 1 reporter line. Returning the first one', expected = 'foo' - - @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( - (('foo', 'bar'), 'More than 1 reporter line. ' - 'Returning the first one', 'foo'), - (None, 'Error parsing reporter line. It is null.', None), - ([], 'Error parsing reporter line. The array is empty', None) - ) - ) - def test_reporter_edge_cases(monkeypatch, input_reporter_line, warning_msg, - expected): - """Test reporter line edge cases""" - - class MockExtractor: - def get_reporter_line(self): - return input_reporter_line - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - metadata = BehaviorMetadata() - - with pytest.warns(UserWarning) as record: -> reporter_line = metadata.reporter_line - -test_behavior_metadata.py:445: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99add9d0> - - @property - def reporter_line(self) -> Optional[str]: -> return self._reporter_line.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:314: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99add290>, input_reporter_line = None, warning_msg = 'Error parsing reporter line. It is null.', expected = None - - @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( - (('foo', 'bar'), 'More than 1 reporter line. ' - 'Returning the first one', 'foo'), - (None, 'Error parsing reporter line. It is null.', None), - ([], 'Error parsing reporter line. The array is empty', None) - ) - ) - def test_reporter_edge_cases(monkeypatch, input_reporter_line, warning_msg, - expected): - """Test reporter line edge cases""" - - class MockExtractor: - def get_reporter_line(self): - return input_reporter_line - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - metadata = BehaviorMetadata() - - with pytest.warns(UserWarning) as record: -> reporter_line = metadata.reporter_line - -test_behavior_metadata.py:445: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a562d0> - - @property - def reporter_line(self) -> Optional[str]: -> return self._reporter_line.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:314: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a56ed0>, input_reporter_line = [], warning_msg = 'Error parsing reporter line. The array is empty', expected = None - - @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( - (('foo', 'bar'), 'More than 1 reporter line. ' - 'Returning the first one', 'foo'), - (None, 'Error parsing reporter line. It is null.', None), - ([], 'Error parsing reporter line. The array is empty', None) - ) - ) - def test_reporter_edge_cases(monkeypatch, input_reporter_line, warning_msg, - expected): - """Test reporter line edge cases""" - - class MockExtractor: - def get_reporter_line(self): - return input_reporter_line - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - metadata = BehaviorMetadata() - - with pytest.warns(UserWarning) as record: -> reporter_line = metadata.reporter_line - -test_behavior_metadata.py:445: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a6f150> - - @property - def reporter_line(self) -> Optional[str]: -> return self._reporter_line.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:314: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a6ffd0> - - def test_age_in_days(monkeypatch): - """Test that age_in_days properly parsed from age""" - - class MockExtractor: - def get_age(self): - return 'P123' - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - -> assert metadata.age_in_days == 123 - -test_behavior_metadata.py:470: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a6ff10> - - @property - def age_in_days(self) -> Optional[int]: -> return self._age.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_age' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:298: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a6f910>, input_age = 'unkown', warning_msg = 'Could not parse numeric age from age code (age code does not start with "P")', expected = None - - @pytest.mark.parametrize("input_age, warning_msg, expected", ( - ('unkown', 'Could not parse numeric age from age code ' - '(age code does not start with "P")', None), - ('P', 'Could not parse numeric age from age code ' - '(no numeric values found in age code)', None) - ) - ) - def test_age_in_days_edge_cases(monkeypatch, input_age, warning_msg, - expected): - """Test age in days edge cases""" - - class MockExtractor: - def get_age(self): - return input_age - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - - with pytest.warns(UserWarning) as record: -> age_in_days = metadata.age_in_days - -test_behavior_metadata.py:501: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a6d750> - - @property - def age_in_days(self) -> Optional[int]: -> return self._age.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_age' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:298: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a6dd50>, input_age = 'P', warning_msg = 'Could not parse numeric age from age code (no numeric values found in age code)', expected = None - - @pytest.mark.parametrize("input_age, warning_msg, expected", ( - ('unkown', 'Could not parse numeric age from age code ' - '(age code does not start with "P")', None), - ('P', 'Could not parse numeric age from age code ' - '(no numeric values found in age code)', None) - ) - ) - def test_age_in_days_edge_cases(monkeypatch, input_age, warning_msg, - expected): - """Test age in days edge cases""" - - class MockExtractor: - def get_age(self): - return input_age - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - - with pytest.warns(UserWarning) as record: -> age_in_days = metadata.age_in_days - -test_behavior_metadata.py:501: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a6d110> - - @property - def age_in_days(self) -> Optional[int]: -> return self._age.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_age' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:298: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a634d0>, tmp_path = PosixPath('/tmp/pytest-of-adam.amster/pytest-0/test_get_date_of_acquisition_t0') -test_params = {'behavior_session_id': 1, 'extractor_expt_date': datetime.datetime(2021, 3, 14, 3, 14, 15), 'pkl_expt_date': datetime.datetime(2021, 3, 14, 3, 14, 15)}, expected_warn_msg = None - - @pytest.mark.parametrize("test_params, expected_warn_msg", [ - # Vanilla test case - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "behavior_session_id": 1 - }, None), - - # pkl expt date stored in unix format - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": 1615716855.0, - "behavior_session_id": 2 - }, None), - - # Extractor and pkl dates differ significantly - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": datetime.strptime("2021-03-14 20:14:15", - "%Y-%m-%d %H:%M:%S"), - "behavior_session_id": 3 - }, - "The `date_of_acquisition` field in LIMS *"), - - # pkl file contains an unparseable datetime - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": None, - "behavior_session_id": 4 - }, - "Could not parse the acquisition datetime *"), - ]) - def test_get_date_of_acquisition(monkeypatch, tmp_path, test_params, - expected_warn_msg): - mock_session_id = test_params["behavior_session_id"] - - pkl_save_path = tmp_path / f"mock_pkl_{mock_session_id}.pkl" - with open(pkl_save_path, 'wb') as handle: - pickle.dump({"start_time": test_params['pkl_expt_date']}, handle) - behavior_stimulus_file = pd.read_pickle(pkl_save_path) - - tz = pytz.timezone("America/Los_Angeles") - extractor_expt_date = tz.localize( - test_params['extractor_expt_date']).astimezone(pytz.utc) - - class MockExtractor(): - def get_date_of_acquisition(self): - return extractor_expt_date - - def get_behavior_session_id(self): - return test_params['behavior_session_id'] - - def get_behavior_stimulus_file(self): - return pkl_save_path - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self, extractor, behavior_stimulus_file): - self._extractor = extractor - self._behavior_stimulus_file = behavior_stimulus_file - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata( - extractor=extractor, - behavior_stimulus_file=behavior_stimulus_file) - - if expected_warn_msg: - with pytest.warns(Warning, match=expected_warn_msg): - obt_date = metadata.date_of_acquisition - else: -> obt_date = metadata.date_of_acquisition - -test_behavior_metadata.py:586: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fcf01f2b9d0> - - @property - def date_of_acquisition(self) -> datetime: -> return self._date_of_acquisition.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_date_of_acquisition' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:310: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a84f90>, tmp_path = PosixPath('/tmp/pytest-of-adam.amster/pytest-0/test_get_date_of_acquisition_t1') -test_params = {'behavior_session_id': 2, 'extractor_expt_date': datetime.datetime(2021, 3, 14, 3, 14, 15), 'pkl_expt_date': 1615716855.0}, expected_warn_msg = None - - @pytest.mark.parametrize("test_params, expected_warn_msg", [ - # Vanilla test case - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "behavior_session_id": 1 - }, None), - - # pkl expt date stored in unix format - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": 1615716855.0, - "behavior_session_id": 2 - }, None), - - # Extractor and pkl dates differ significantly - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": datetime.strptime("2021-03-14 20:14:15", - "%Y-%m-%d %H:%M:%S"), - "behavior_session_id": 3 - }, - "The `date_of_acquisition` field in LIMS *"), - - # pkl file contains an unparseable datetime - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": None, - "behavior_session_id": 4 - }, - "Could not parse the acquisition datetime *"), - ]) - def test_get_date_of_acquisition(monkeypatch, tmp_path, test_params, - expected_warn_msg): - mock_session_id = test_params["behavior_session_id"] - - pkl_save_path = tmp_path / f"mock_pkl_{mock_session_id}.pkl" - with open(pkl_save_path, 'wb') as handle: - pickle.dump({"start_time": test_params['pkl_expt_date']}, handle) - behavior_stimulus_file = pd.read_pickle(pkl_save_path) - - tz = pytz.timezone("America/Los_Angeles") - extractor_expt_date = tz.localize( - test_params['extractor_expt_date']).astimezone(pytz.utc) - - class MockExtractor(): - def get_date_of_acquisition(self): - return extractor_expt_date - - def get_behavior_session_id(self): - return test_params['behavior_session_id'] - - def get_behavior_stimulus_file(self): - return pkl_save_path - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self, extractor, behavior_stimulus_file): - self._extractor = extractor - self._behavior_stimulus_file = behavior_stimulus_file - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata( - extractor=extractor, - behavior_stimulus_file=behavior_stimulus_file) - - if expected_warn_msg: - with pytest.warns(Warning, match=expected_warn_msg): - obt_date = metadata.date_of_acquisition - else: -> obt_date = metadata.date_of_acquisition - -test_behavior_metadata.py:586: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a84950> - - @property - def date_of_acquisition(self) -> datetime: -> return self._date_of_acquisition.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_date_of_acquisition' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:310: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a84fd0>, tmp_path = PosixPath('/tmp/pytest-of-adam.amster/pytest-0/test_get_date_of_acquisition_t2') -test_params = {'behavior_session_id': 3, 'extractor_expt_date': datetime.datetime(2021, 3, 14, 3, 14, 15), 'pkl_expt_date': datetime.datetime(2021, 3, 14, 20, 14, 15)}, expected_warn_msg = 'The `date_of_acquisition` field in LIMS *' - - @pytest.mark.parametrize("test_params, expected_warn_msg", [ - # Vanilla test case - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "behavior_session_id": 1 - }, None), - - # pkl expt date stored in unix format - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": 1615716855.0, - "behavior_session_id": 2 - }, None), - - # Extractor and pkl dates differ significantly - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": datetime.strptime("2021-03-14 20:14:15", - "%Y-%m-%d %H:%M:%S"), - "behavior_session_id": 3 - }, - "The `date_of_acquisition` field in LIMS *"), - - # pkl file contains an unparseable datetime - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": None, - "behavior_session_id": 4 - }, - "Could not parse the acquisition datetime *"), - ]) - def test_get_date_of_acquisition(monkeypatch, tmp_path, test_params, - expected_warn_msg): - mock_session_id = test_params["behavior_session_id"] - - pkl_save_path = tmp_path / f"mock_pkl_{mock_session_id}.pkl" - with open(pkl_save_path, 'wb') as handle: - pickle.dump({"start_time": test_params['pkl_expt_date']}, handle) - behavior_stimulus_file = pd.read_pickle(pkl_save_path) - - tz = pytz.timezone("America/Los_Angeles") - extractor_expt_date = tz.localize( - test_params['extractor_expt_date']).astimezone(pytz.utc) - - class MockExtractor(): - def get_date_of_acquisition(self): - return extractor_expt_date - - def get_behavior_session_id(self): - return test_params['behavior_session_id'] - - def get_behavior_stimulus_file(self): - return pkl_save_path - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self, extractor, behavior_stimulus_file): - self._extractor = extractor - self._behavior_stimulus_file = behavior_stimulus_file - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata( - extractor=extractor, - behavior_stimulus_file=behavior_stimulus_file) - - if expected_warn_msg: - with pytest.warns(Warning, match=expected_warn_msg): -> obt_date = metadata.date_of_acquisition - -test_behavior_metadata.py:584: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fcf01f2b910> - - @property - def date_of_acquisition(self) -> datetime: -> return self._date_of_acquisition.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_date_of_acquisition' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:310: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a4fe90>, tmp_path = PosixPath('/tmp/pytest-of-adam.amster/pytest-0/test_get_date_of_acquisition_t3') -test_params = {'behavior_session_id': 4, 'extractor_expt_date': datetime.datetime(2021, 3, 14, 3, 14, 15), 'pkl_expt_date': None}, expected_warn_msg = 'Could not parse the acquisition datetime *' - - @pytest.mark.parametrize("test_params, expected_warn_msg", [ - # Vanilla test case - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "behavior_session_id": 1 - }, None), - - # pkl expt date stored in unix format - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": 1615716855.0, - "behavior_session_id": 2 - }, None), - - # Extractor and pkl dates differ significantly - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": datetime.strptime("2021-03-14 20:14:15", - "%Y-%m-%d %H:%M:%S"), - "behavior_session_id": 3 - }, - "The `date_of_acquisition` field in LIMS *"), - - # pkl file contains an unparseable datetime - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": None, - "behavior_session_id": 4 - }, - "Could not parse the acquisition datetime *"), - ]) - def test_get_date_of_acquisition(monkeypatch, tmp_path, test_params, - expected_warn_msg): - mock_session_id = test_params["behavior_session_id"] - - pkl_save_path = tmp_path / f"mock_pkl_{mock_session_id}.pkl" - with open(pkl_save_path, 'wb') as handle: - pickle.dump({"start_time": test_params['pkl_expt_date']}, handle) - behavior_stimulus_file = pd.read_pickle(pkl_save_path) - - tz = pytz.timezone("America/Los_Angeles") - extractor_expt_date = tz.localize( - test_params['extractor_expt_date']).astimezone(pytz.utc) - - class MockExtractor(): - def get_date_of_acquisition(self): - return extractor_expt_date - - def get_behavior_session_id(self): - return test_params['behavior_session_id'] - - def get_behavior_stimulus_file(self): - return pkl_save_path - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self, extractor, behavior_stimulus_file): - self._extractor = extractor - self._behavior_stimulus_file = behavior_stimulus_file - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata( - extractor=extractor, - behavior_stimulus_file=behavior_stimulus_file) - - if expected_warn_msg: - with pytest.warns(Warning, match=expected_warn_msg): -> obt_date = metadata.date_of_acquisition - -test_behavior_metadata.py:584: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a4f490> - - @property - def date_of_acquisition(self) -> datetime: -> return self._date_of_acquisition.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_date_of_acquisition' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:310: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a4f050> - - def test_indicator(monkeypatch): - """Test that indicator is parsed from full_genotype""" - - class MockExtractor: - def get_reporter_line(self): - return 'Ai148(TIT2L-GC6f-ICL-tTA2)' - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - -> assert metadata.indicator == 'GCaMP6f' - -test_behavior_metadata.py:610: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a818d0> - - @property - def indicator(self) -> Optional[str]: -> return self._reporter_line.indicator -E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:318: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a81b10>, input_reporter_line = None, warning_msg = 'Error parsing reporter line. It is null.', expected = None - - @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( - (None, 'Error parsing reporter line. It is null.', None), - ('foo', 'Could not parse indicator from reporter because none' - 'of the expected substrings were found in the reporter', None) - ) - ) - def test_indicator_edge_cases(monkeypatch, input_reporter_line, warning_msg, - expected): - """Test indicator parsing edge cases""" - - class MockExtractor: - def get_reporter_line(self): - return input_reporter_line - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - - with pytest.warns(UserWarning) as record: -> indicator = metadata.indicator - -test_behavior_metadata.py:640: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99a815d0> - - @property - def indicator(self) -> Optional[str]: -> return self._reporter_line.indicator -E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:318: AttributeErrormonkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99ab1dd0>, input_reporter_line = 'foo', warning_msg = 'Could not parse indicator from reporter because noneof the expected substrings were found in the reporter' -expected = None - - @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( - (None, 'Error parsing reporter line. It is null.', None), - ('foo', 'Could not parse indicator from reporter because none' - 'of the expected substrings were found in the reporter', None) - ) - ) - def test_indicator_edge_cases(monkeypatch, input_reporter_line, warning_msg, - expected): - """Test indicator parsing edge cases""" - - class MockExtractor: - def get_reporter_line(self): - return input_reporter_line - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - - with pytest.warns(UserWarning) as record: -> indicator = metadata.indicator - -test_behavior_metadata.py:640: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce99ab1fd0> - - @property - def indicator(self) -> Optional[str]: -> return self._reporter_line.indicator -E AttributeError: 'BehaviorMetadata' object has no attribute '_reporter_line' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:318: AttributeErrorself = <allensdk.brain_observatory.behavior.session_apis.data_transforms.behavior_ophys_data_transforms.BehaviorOphysDataTransforms object at 0x7fce9b1abfd0> - - def _load_stimulus_timestamps_and_delay(self): - """ - Load the stimulus timestamps (uncorrected for - monitor delay) and the monitor delay - """ - sync_path = self.extractor.get_sync_file() - aligner = OphysTimeAligner(sync_file=sync_path) - (self._stimulus_timestamps, - delta) = aligner.clipped_stim_timestamps - - try: -> delay = aligner.monitor_delay - -../../../brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py:163: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.internal.brain_observatory.time_sync.OphysTimeAligner object at 0x7fce9b1ab350> - - @property - def monitor_delay(self): - """ - The monitor delay (in seconds) associated with the session - """ - if self._monitor_delay is None: -> self._monitor_delay = self._get_monitor_delay() - -../../../internal/brain_observatory/time_sync.py:393: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.internal.brain_observatory.time_sync.OphysTimeAligner object at 0x7fce9b1ab350> - - def dummy_delay(self): -> raise ValueError("that did not work") -E ValueError: that did not work - -test_behavior_ophys_data_xforms.py:431: ValueError - -During handling of the above exception, another exception occurred: - -monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fce99a6d6d0> - - def test_monitor_delay(monkeypatch): - """ - Check that BehaviorOphysDataTransforms can handle all - edge cases of monitor delay calculation - """ - - # first test case where monitor delay calculation succeeds - class DummyExtractor(object): - def get_sync_file(self): - return '' - - def get_equipment_name(self): - return 'spam' - - def xform_init(self): - self.extractor = DummyExtractor() - - def aligner_init(self, sync_file=None): - self._monitor_delay = None - self._clipped_stim_ts_delta = None - - def dummy_clipped(self): - return np.array([1, 2, 3, 4, 5], dtype=int), -1 - - def dummy_delay(self): - return 1.12 - - with monkeypatch.context() as ctx: - ctx.setattr(BehaviorOphysDataTransforms, - '__init__', - xform_init) - - ctx.setattr(OphysTimeAligner, - '__init__', - aligner_init) - - ctx.setattr(OphysTimeAligner, - '_get_clipped_stim_timestamps', - dummy_clipped) - - ctx.setattr(OphysTimeAligner, - '_get_monitor_delay', - dummy_delay) - - xforms = BehaviorOphysDataTransforms() - assert abs(xforms.get_monitor_delay() - 1.12) < 1.0e-6 - np.testing.assert_array_equal(xforms.get_stimulus_timestamps(), - np.array([1, 2, 3, 4, 5], dtype=int)) - - # now try case where monitor delay fails, but value can - # be looked up - def dummy_delay(self): - raise ValueError("that did not work") - - delay_lookup = {'CAM2P.1': 0.020842, - 'CAM2P.2': 0.037566, - 'CAM2P.3': 0.021390, - 'CAM2P.4': 0.021102, - 'CAM2P.5': 0.021192, - 'MESO.1': 0.03613} - - def dummy_get_metadata(self): - def dummy_metadata_init(self, extractor): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_metadata_init) - - class DummyExtractor: - def get_sync_file(self): - return '' - - def get_equipment_name(self): - return equipment_name - - metadata = BehaviorMetadata( - extractor=DummyExtractor()) - return metadata - - for equipment_name in delay_lookup.keys(): - expected_delay = delay_lookup[equipment_name] - - with monkeypatch.context() as ctx: - ctx.setattr(BehaviorOphysDataTransforms, - '__init__', - xform_init) - - ctx.setattr(BehaviorOphysDataTransforms, - 'get_metadata', - dummy_get_metadata) - - ctx.setattr(OphysTimeAligner, - '__init__', - aligner_init) - - ctx.setattr(OphysTimeAligner, - '_get_clipped_stim_timestamps', - dummy_clipped) - - ctx.setattr(OphysTimeAligner, - '_get_monitor_delay', - dummy_delay) - - xforms = BehaviorOphysDataTransforms() - with pytest.warns(UserWarning): -> m = xforms.get_monitor_delay() - -test_behavior_ophys_data_xforms.py:485: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ -../../../brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py:207: in get_monitor_delay - self._load_stimulus_timestamps_and_delay() -../../../brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py:165: in _load_stimulus_timestamps_and_delay - equipment_name = self.get_metadata().equipment_name -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.data_objects.metadata.behavior_metadata.behavior_metadata.BehaviorMetadata object at 0x7fce9b22c810> - - @property - def equipment_name(self) -> str: -> return self._equipment_name.value -E AttributeError: 'BehaviorMetadata' object has no attribute '_equipment_name' - -../../../brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py:290: AttributeError/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:22: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:22: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:43: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:62: this test is either time/memory/compute expensive or it depends on resources internal to the Allen Institute. Either way, it does'nt run by default and must be opted into (it does run in our nightly builds)./home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:144: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:159: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:159: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:170: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:170: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:223: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py:246: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightlydef test_behavior_ophys_experiment_list_data_attributes_and_methods(): - # Test that data related methods/attributes/properties for - # BehaviorOphysExperiment are returned properly. - - # This test will need to be updated if: - # 1. Data being returned by class has changed - # 2. Inheritance of class has changed - expected = { - 'average_projection', - 'behavior_session_id', - 'cell_specimen_table', - 'corrected_fluorescence_traces', - 'dff_traces', - 'events', - 'eye_tracking', - 'eye_tracking_rig_geometry', - 'get_cell_specimen_ids', - 'get_cell_specimen_indices', - 'get_dff_traces', - 'get_performance_metrics', - 'get_reward_rate', - 'get_rolling_performance_df', - 'get_segmentation_mask_image', - 'licks', - 'max_projection', - 'metadata', - 'motion_correction', - 'ophys_experiment_id', - 'ophys_session_id', - 'ophys_timestamps', - 'raw_running_speed', - 'rewards', - 'roi_masks', - 'running_speed', - 'segmentation_mask_image', - 'stimulus_presentations', - 'stimulus_templates', - 'stimulus_timestamps', - 'task_parameters', - 'trials' - } - - behavior_ophys_experiment = BehaviorOphysExperiment(api=MagicMock()) - obt = behavior_ophys_experiment.list_data_attributes_and_methods() - -> assert any(expected ^ set(obt)) is False -E AssertionError: assert True is False -E + where True = any(({'average_projection', 'behavior_session_id', 'cell_specimen_table', 'corrected_fluorescence_traces', 'dff_traces', 'events', ...} ^ {'average_projection', 'behavior_session_id', 'cell_specimen_table', 'corrected_fluorescence_traces', 'dff_traces', 'events', ...})) -E + where {'average_projection', 'behavior_session_id', 'cell_specimen_table', 'corrected_fluorescence_traces', 'dff_traces', 'events', ...} = set(['average_projection', 'behavior_session_id', 'cell_specimen_table', 'corrected_fluorescence_traces', 'dff_traces', 'events', ...]) - -test_behavior_ophys_experiment.py:300: AssertionError/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_lims_api.py:27: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_lims_api.py:36: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_lims_api.py:36: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_lims_api.py:59: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_lims_api.py:82: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_behavior_ophys_lims_api.py:447: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightlydef test_behavior_session_list_data_attributes_and_methods(): - # Test that data related methods/attributes/properties for - # BehaviorSession are returned properly. - - # This test will need to be updated if: - # 1. Data being returned by class has changed - # 2. Inheritance of class has changed - expected = { - 'behavior_session_id', - 'get_performance_metrics', - 'get_reward_rate', - 'get_rolling_performance_df', - 'licks', - 'metadata', - 'raw_running_speed', - 'rewards', - 'running_speed', - 'stimulus_presentations', - 'stimulus_templates', - 'stimulus_timestamps', - 'task_parameters', - 'trials' - } - - behavior_session = BehaviorSession(api=MagicMock()) - obt = behavior_session.list_data_attributes_and_methods() - -> assert any(expected ^ set(obt)) is False -E AssertionError: assert True is False -E + where True = any(({'behavior_session_id', 'get_performance_metrics', 'get_reward_rate', 'get_rolling_performance_df', 'licks', 'metadata', ...} ^ {'behavior_session_id', 'from_internal_mixed', 'from_nwb', 'get_performance_metrics', 'get_reward_rate', 'get_rolling_performance_df', ...})) -E + where {'behavior_session_id', 'from_internal_mixed', 'from_nwb', 'get_performance_metrics', 'get_reward_rate', 'get_rolling_performance_df', ...} = set(['behavior_session_id', 'from_internal_mixed', 'from_nwb', 'get_performance_metrics', 'get_reward_rate', 'get_rolling_performance_df', ...]) - -test_behavior_session.py:99: AssertionError/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:64: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:64: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:76: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:76: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:88: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:88: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:100: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:100: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:112: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:112: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:124: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:124: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:136: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:136: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:148: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:148: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:160: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:160: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:172: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:172: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:184: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:184: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:196: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:196: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:208: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:208: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:220: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:220: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:241: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:250: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:250: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:268: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:268: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:286: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_ophys_lims_api.py:286: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:21: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:28: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:42: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:49: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:58: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:58: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:58: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:70: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:70: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:70: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:82: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:90: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:96: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:103: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:113: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:123: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:129: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:135: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_swdb_behavior_project_cache.py:141: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_sync_processing.py:24: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_trials_processing.py:11: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightly/home/adam.amster/AllenSDK/allensdk/test/brain_observatory/behavior/test_trials_processing.py:11: this test depends on the resources only available to Bamboo agents, but are still fast. If they are slow, mark with nightlynwbfile = root pynwb.file.NWBFile at 0x140525322581840 -Fields: - acquisition: { - v_in <class 'pynwb.base.TimeSeries'>, - v_...n - session_start_time: 2021-06-04 07:15:24.143189-07:00 - timestamps_reference_time: 2021-06-04 07:15:24.143189-07:00 - -roundtrip = True, roundtripper = <function roundtripper.<locals>.f at 0x7fce8e1ed950> -running_acquisition_df_fixture = dx v_sig v_in -timestamps -1.0 1 1 1 -2.0 1 1 1 -3.0 1 1 1 - - @pytest.mark.parametrize('roundtrip', [True, False]) - def test_add_running_acquisition_to_nwbfile(nwbfile, roundtrip, roundtripper, - running_acquisition_df_fixture): - nwbfile = nwb.add_running_acquisition_to_nwbfile( - nwbfile, running_acquisition_df_fixture) - - if roundtrip: - obt = roundtripper(nwbfile, BehaviorNwbApi) - else: - obt = BehaviorNwbApi.from_nwbfile(nwbfile) - -> obt_running_acq_df = obt.get_running_acquisition_df() - -test_write_behavior_nwb.py:38: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.session_apis.data_io.behavior_nwb_api.BehaviorNwbApi object at 0x7fce9b326140> - - def get_running_acquisition_df(self): -> raise NotImplementedError() -E NotImplementedError - -../../../brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py:121: NotImplementedErrornwbfile = root pynwb.file.NWBFile at 0x140525180967888 -Fields: - acquisition: { - v_in <class 'pynwb.base.TimeSeries'>, - v_...n - session_start_time: 2021-06-04 07:15:24.611157-07:00 - timestamps_reference_time: 2021-06-04 07:15:24.611157-07:00 - -roundtrip = False, roundtripper = <function roundtripper.<locals>.f at 0x7fce92606440> -running_acquisition_df_fixture = dx v_sig v_in -timestamps -1.0 1 1 1 -2.0 1 1 1 -3.0 1 1 1 - - @pytest.mark.parametrize('roundtrip', [True, False]) - def test_add_running_acquisition_to_nwbfile(nwbfile, roundtrip, roundtripper, - running_acquisition_df_fixture): - nwbfile = nwb.add_running_acquisition_to_nwbfile( - nwbfile, running_acquisition_df_fixture) - - if roundtrip: - obt = roundtripper(nwbfile, BehaviorNwbApi) - else: - obt = BehaviorNwbApi.from_nwbfile(nwbfile) - -> obt_running_acq_df = obt.get_running_acquisition_df() - -test_write_behavior_nwb.py:38: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.session_apis.data_io.behavior_nwb_api.BehaviorNwbApi object at 0x7fce92602cd0> - - def get_running_acquisition_df(self): -> raise NotImplementedError() -E NotImplementedError - -../../../brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py:121: NotImplementedErrornwbfile = root pynwb.file.NWBFile at 0x140525180557392 -Fields: - file_create_date: [datetime.datetime(2021, 6, 4, 7, 15, 24, 622...n - session_start_time: 2021-06-04 07:15:24.621814-07:00 - timestamps_reference_time: 2021-06-04 07:15:24.621814-07:00 - -running_speed = RunningSpeed(timestamps=[1.0, 2.0, 3.0], values=[4, 5, 6]), roundtrip = True, roundtripper = <function roundtripper.<locals>.f at 0x7fce926065f0> - - @pytest.mark.parametrize('roundtrip', [True, False]) - def test_add_running_speed_to_nwbfile(nwbfile, running_speed, - roundtrip, roundtripper): - - nwbfile = nwb.add_running_speed_to_nwbfile(nwbfile, running_speed) - - if roundtrip: - obt = roundtripper(nwbfile, BehaviorNwbApi) - else: - obt = BehaviorNwbApi.from_nwbfile(nwbfile) - -> obt_running_speed = obt.get_running_speed() - -test_write_behavior_nwb.py:56: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.session_apis.data_io.behavior_nwb_api.BehaviorNwbApi object at 0x7fce925f48c0> - - def get_running_speed(self): -> raise NotImplementedError() -E NotImplementedError - -../../../brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py:124: NotImplementedErrornwbfile = root pynwb.file.NWBFile at 0x140525180835984 -Fields: - file_create_date: [datetime.datetime(2021, 6, 4, 7, 15, 25, 126...n - session_start_time: 2021-06-04 07:15:25.126058-07:00 - timestamps_reference_time: 2021-06-04 07:15:25.126058-07:00 - -running_speed = RunningSpeed(timestamps=[1.0, 2.0, 3.0], values=[4, 5, 6]), roundtrip = False, roundtripper = <function roundtripper.<locals>.f at 0x7fce8e1edb90> - - @pytest.mark.parametrize('roundtrip', [True, False]) - def test_add_running_speed_to_nwbfile(nwbfile, running_speed, - roundtrip, roundtripper): - - nwbfile = nwb.add_running_speed_to_nwbfile(nwbfile, running_speed) - - if roundtrip: - obt = roundtripper(nwbfile, BehaviorNwbApi) - else: - obt = BehaviorNwbApi.from_nwbfile(nwbfile) - -> obt_running_speed = obt.get_running_speed() - -test_write_behavior_nwb.py:56: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <allensdk.brain_observatory.behavior.session_apis.data_io.behavior_nwb_api.BehaviorNwbApi object at 0x7fce922053c0> - - def get_running_speed(self): -> raise NotImplementedError() -E NotImplementedError - -../../../brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py:124: NotImplementedError \ No newline at end of file From 5fbfd2f22072ac50be303d245ca20cdd2862c034 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 7 Jun 2021 14:26:40 -0700 Subject: [PATCH 023/234] Rename mixin to interface; remove unused methods from DataObject --- .../behavior/behavior_session.py | 13 ++++++++----- .../__init__.py | 0 .../internal_mixed_readable_interface.py} | 6 +++--- .../json_readable_interface.py} | 2 +- .../lims_readable_interface.py} | 2 +- .../stimulus_file_readable_interface.py} | 5 ++--- .../sync_file_readable_interface.py} | 5 ++--- .../__init__.py | 0 .../nwb_writable_interface.py} | 2 +- .../behavior_metadata/behavior_metadata.py | 16 ++++++++-------- .../behavior_metadata/behavior_session_id.py | 8 ++++---- .../behavior_session_uuid.py | 8 ++++---- .../behavior_metadata/date_of_acquisition.py | 8 ++++---- .../metadata/behavior_metadata/foraging_id.py | 11 ++++------- .../behavior_metadata/session_type.py | 8 ++++---- .../behavior_metadata/stimulus_frame_rate.py | 8 ++++---- .../metadata/subject_metadata/driver_line.py | 8 ++++---- .../subject_metadata/full_genotype.py | 8 ++++---- .../metadata/subject_metadata/mouse_id.py | 8 ++++---- .../subject_metadata/reporter_line.py | 11 ++++------- .../metadata/subject_metadata/sex.py | 8 ++++---- .../subject_metadata/subject_metadata.py | 16 ++++++++-------- .../running_speed/running_acquisition.py | 5 ++++- .../running_speed/running_speed.py | 5 ++++- .../stimulus_timestamps.py | 19 +++++++++++-------- 25 files changed, 97 insertions(+), 93 deletions(-) rename allensdk/brain_observatory/behavior/data_objects/_base/{readable_mixins => readable_interfaces}/__init__.py (100%) rename allensdk/brain_observatory/behavior/data_objects/_base/{readable_mixins/internal_mixed_readable_mixin.py => readable_interfaces/internal_mixed_readable_interface.py} (71%) rename allensdk/brain_observatory/behavior/data_objects/_base/{readable_mixins/json_readable_mixin.py => readable_interfaces/json_readable_interface.py} (93%) rename allensdk/brain_observatory/behavior/data_objects/_base/{readable_mixins/lims_readable_mixin.py => readable_interfaces/lims_readable_interface.py} (93%) rename allensdk/brain_observatory/behavior/data_objects/_base/{readable_mixins/stimulus_file_readable_mixin.py => readable_interfaces/stimulus_file_readable_interface.py} (77%) rename allensdk/brain_observatory/behavior/data_objects/_base/{readable_mixins/sync_file_readable_mixin.py => readable_interfaces/sync_file_readable_interface.py} (78%) rename allensdk/brain_observatory/behavior/data_objects/_base/{writable_mixins => writable_interfaces}/__init__.py (100%) rename allensdk/brain_observatory/behavior/data_objects/_base/{writable_mixins/nwb_writable_mixin.py => writable_interfaces/nwb_writable_interface.py} (94%) diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index 37a0ef674..2fbfe987d 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -8,9 +8,12 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_files import StimulusFile -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .internal_mixed_readable_mixin import \ - InternalMixedReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .internal_mixed_readable_interface import \ + InternalMixedReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.nwb_writable_interface import \ + NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_metadata import \ BehaviorMetadata @@ -34,8 +37,8 @@ BehaviorDataApi = Type[BehaviorBase] -class BehaviorSession(DataObject, InternalMixedReadableMixin, - LazyPropertyMixin): +class BehaviorSession(DataObject, InternalMixedReadableInterface, + NwbWritableInterface, LazyPropertyMixin): def __init__( self, api: Optional[BehaviorDataApi] = None, behavior_session_id: BehaviorSessionId = None, diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/__init__.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/__init__.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/__init__.py rename to allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/__init__.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/internal_mixed_readable_mixin.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/internal_mixed_readable_interface.py similarity index 71% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/internal_mixed_readable_mixin.py rename to allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/internal_mixed_readable_interface.py index a50d3e15c..89e21d2dd 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/internal_mixed_readable_mixin.py +++ b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/internal_mixed_readable_interface.py @@ -3,13 +3,13 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject -class InternalMixedReadableMixin: +class InternalMixedReadableInterface(abc.ABC): """Marks a data object as readable from a variety of internal data sources """ @classmethod @abc.abstractmethod - def from_internal_mixed(cls, *args) -> "DataObject": # pragma: no cover - """Populate a DataObject from various internal data sources + def from_onprem(cls, *args) -> "DataObject": # pragma: no cover + """Populate a DataObject from various on-prem data sources Returns ------- diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/json_readable_mixin.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/json_readable_interface.py similarity index 93% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/json_readable_mixin.py rename to allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/json_readable_interface.py index 5bc8fe3e6..8421c94cc 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/json_readable_mixin.py +++ b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/json_readable_interface.py @@ -3,7 +3,7 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject -class JsonReadableMixin: +class JsonReadableInterface(abc.ABC): """Marks a data object as readable from json""" @classmethod @abc.abstractmethod diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/lims_readable_mixin.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/lims_readable_interface.py similarity index 93% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/lims_readable_mixin.py rename to allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/lims_readable_interface.py index 8f77aca48..88ee206a6 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/lims_readable_mixin.py +++ b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/lims_readable_interface.py @@ -3,7 +3,7 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject -class LimsReadableMixin: +class LimsReadableInterface(abc.ABC): """Marks a data object as readable from LIMS""" @classmethod @abc.abstractmethod diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/stimulus_file_readable_mixin.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/stimulus_file_readable_interface.py similarity index 77% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/stimulus_file_readable_mixin.py rename to allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/stimulus_file_readable_interface.py index 0645bb62a..9b2ec7507 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/stimulus_file_readable_mixin.py +++ b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/stimulus_file_readable_interface.py @@ -3,12 +3,11 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject -class StimulusFileReadableMixin: +class StimulusFileReadableInterface(abc.ABC): """Marks a data object as readable from stimulus file""" @classmethod @abc.abstractmethod - def from_stimulus_file(cls, *args) \ - -> "DataObject": # pragma: no cover + def from_stimulus_file(cls, *args) -> "DataObject": """Populate a DataObject from the stimulus file Returns diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/sync_file_readable_mixin.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/sync_file_readable_interface.py similarity index 78% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/sync_file_readable_mixin.py rename to allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/sync_file_readable_interface.py index bbcb7850b..ec2587a99 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_base/readable_mixins/sync_file_readable_mixin.py +++ b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/sync_file_readable_interface.py @@ -3,12 +3,11 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject -class SyncFileReadableMixin: +class SyncFileReadableInterface(abc.ABC): """Marks a data object as readable from sync file""" @classmethod @abc.abstractmethod - def from_sync_file(cls, *args) \ - -> "DataObject": # pragma: no cover + def from_sync_file(cls, *args) -> "DataObject": """Populate a DataObject from the sync file Returns diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/writable_mixins/__init__.py b/allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/__init__.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/writable_mixins/__init__.py rename to allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/__init__.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/writable_mixins/nwb_writable_mixin.py b/allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/nwb_writable_interface.py similarity index 94% rename from allensdk/brain_observatory/behavior/data_objects/_base/writable_mixins/nwb_writable_mixin.py rename to allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/nwb_writable_interface.py index 1070dca21..fc00f7eaf 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_base/writable_mixins/nwb_writable_mixin.py +++ b/allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/nwb_writable_interface.py @@ -5,7 +5,7 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject -class NwbWritableMixin: +class NwbWritableInterface(abc.ABC): """Marks a data object as writable to NWB""" @classmethod @abc.abstractmethod diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index 6a32a8e45..4297a3f91 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -8,13 +8,13 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject, \ StimulusTimestamps, BehaviorSessionId -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .internal_mixed_readable_mixin \ +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .internal_mixed_readable_interface \ import \ - InternalMixedReadableMixin -from allensdk.brain_observatory.behavior.data_objects._base.writable_mixins\ - .nwb_writable_mixin import \ - NwbWritableMixin + InternalMixedReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base.writable_interfaces\ + .nwb_writable_interface import \ + NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_session_uuid import \ BehaviorSessionUUID @@ -178,8 +178,8 @@ def get_task_parameters(data: Dict) -> Dict: return task_parameters -class BehaviorMetadata(DataObject, InternalMixedReadableMixin, - NwbWritableMixin): +class BehaviorMetadata(DataObject, InternalMixedReadableInterface, + NwbWritableInterface): """Container class for behavior metadata""" def __init__(self, behavior_session_id: BehaviorSessionId, diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py index 7a8b6e58a..244d76e45 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py @@ -3,9 +3,9 @@ from cachetools import cached, LRUCache from cachetools.keys import hashkey -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .lims_readable_mixin import \ - LimsReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .lims_readable_interface import \ + LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin from allensdk.brain_observatory.behavior.data_objects import DataObject @@ -14,7 +14,7 @@ def from_lims_cache_key(cls, db, ophys_experiment_id: int): return hashkey(ophys_experiment_id) -class BehaviorSessionId(DataObject, LimsReadableMixin): +class BehaviorSessionId(DataObject, LimsReadableInterface): def __init__(self, behavior_session_id: int): super().__init__(name="behavior_session_id", value=behavior_session_id) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py index b1c8c1038..9ba0155f3 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py @@ -5,12 +5,12 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .stimulus_file_readable_mixin import \ - StimulusFileReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .stimulus_file_readable_interface import \ + StimulusFileReadableInterface -class BehaviorSessionUUID(DataObject, StimulusFileReadableMixin): +class BehaviorSessionUUID(DataObject, StimulusFileReadableInterface): """the universally unique identifier (UUID)""" def __init__(self, behavior_session_uuid: Optional[uuid.UUID]): super().__init__(name="behavior_session_uuid", value=behavior_session_uuid) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py index 41326520f..cbf269673 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py @@ -6,13 +6,13 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .lims_readable_mixin import \ - LimsReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .lims_readable_interface import \ + LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin -class DateOfAcquisition(DataObject, LimsReadableMixin): +class DateOfAcquisition(DataObject, LimsReadableInterface): """timestamp for when experiment was started in UTC""" def __init__(self, date_of_acquisition: float): super().__init__(name="date_of_acquisition", value=date_of_acquisition) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py index af29f1d2b..9ea841b11 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py @@ -3,13 +3,13 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .lims_readable_mixin import \ - LimsReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .lims_readable_interface import \ + LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin -class ForagingId(DataObject, LimsReadableMixin): +class ForagingId(DataObject, LimsReadableInterface): """Foraging id""" def __init__(self, foraging_id: uuid.UUID): super().__init__(name="foraging_id", value=foraging_id) @@ -39,6 +39,3 @@ def from_lims(cls, behavior_session_id: int, @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "ForagingId": pass - - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass \ No newline at end of file diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py index 19876160b..25d08d62c 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py @@ -2,13 +2,13 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .stimulus_file_readable_mixin \ +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .stimulus_file_readable_interface \ import \ - StimulusFileReadableMixin + StimulusFileReadableInterface -class SessionType(DataObject, StimulusFileReadableMixin): +class SessionType(DataObject, StimulusFileReadableInterface): """the stimulus set used""" def __init__(self, session_type: str): super().__init__(name="session_type", value=session_type) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py index d2b0b25cc..669268dfc 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py @@ -2,13 +2,13 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject, \ StimulusTimestamps -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .stimulus_file_readable_mixin \ +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .stimulus_file_readable_interface \ import \ - StimulusFileReadableMixin + StimulusFileReadableInterface -class StimulusFrameRate(DataObject, StimulusFileReadableMixin): +class StimulusFrameRate(DataObject, StimulusFileReadableInterface): """Stimulus frame rate""" def __init__(self, stimulus_frame_rate: float): super().__init__(name="stimulus_frame_rate", value=stimulus_frame_rate) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py index 0f9b3c509..b2124652a 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py @@ -3,14 +3,14 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .lims_readable_mixin import \ - LimsReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .lims_readable_interface import \ + LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin, \ OneOrMoreResultExpectedError -class DriverLine(DataObject, LimsReadableMixin): +class DriverLine(DataObject, LimsReadableInterface): """the genotype name(s) of the driver line(s)""" def __init__(self, driver_line: List[str]): super().__init__(name="driver_line", value=driver_line) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py index bd288ef49..ac42044a2 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py @@ -4,13 +4,13 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .lims_readable_mixin import \ - LimsReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .lims_readable_interface import \ + LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin -class FullGenotype(DataObject, LimsReadableMixin): +class FullGenotype(DataObject, LimsReadableInterface): """the name of the subject's genotype""" def __init__(self, full_genotype: str): super().__init__(name="full_genotype", value=full_genotype) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py index 59e4fbc4b..4aa00e213 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py @@ -1,13 +1,13 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .lims_readable_mixin import \ - LimsReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .lims_readable_interface import \ + LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin -class MouseId(DataObject, LimsReadableMixin): +class MouseId(DataObject, LimsReadableInterface): """the LabTracks ID""" def __init__(self, mouse_id: int): super().__init__(name="mouse_id", value=mouse_id) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py index d528ac797..a56b8fb70 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py @@ -4,14 +4,14 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .lims_readable_mixin import \ - LimsReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .lims_readable_interface import \ + LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin, \ OneOrMoreResultExpectedError -class ReporterLine(DataObject, LimsReadableMixin): +class ReporterLine(DataObject, LimsReadableInterface): """the genotype name(s) of the reporter line(s)""" def __init__(self, reporter_line: Optional[str]): super().__init__(name="reporter_line", value=reporter_line) @@ -48,9 +48,6 @@ def from_lims(cls, behavior_session_id: int, def from_nwb(cls, nwbfile: NWBFile) -> "ReporterLine": return cls(reporter_line=nwbfile.subject.reporter_line) - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass - @staticmethod def _parse(reporter_line: Optional[List[str]], warn=False) -> Optional[str]: diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py index 252880172..d48076d89 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py @@ -1,13 +1,13 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .lims_readable_mixin import \ - LimsReadableMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .lims_readable_interface import \ + LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin -class Sex(DataObject, LimsReadableMixin): +class Sex(DataObject, LimsReadableInterface): """sex of the animal (M/F)""" def __init__(self, sex: str): super().__init__(name="sex", value=sex) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py index d58948755..b7a75d524 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py @@ -4,12 +4,12 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject, \ BehaviorSessionId -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .lims_readable_mixin import \ - LimsReadableMixin -from allensdk.brain_observatory.behavior.data_objects._base.writable_mixins\ - .nwb_writable_mixin import \ - NwbWritableMixin +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .lims_readable_interface import \ + LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base.writable_interfaces\ + .nwb_writable_interface import \ + NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ .subject_metadata.age import \ Age @@ -33,8 +33,8 @@ from allensdk.internal.api import PostgresQueryMixin -class SubjectMetadata(DataObject, LimsReadableMixin, - NwbWritableMixin): +class SubjectMetadata(DataObject, LimsReadableInterface, + NwbWritableInterface): """Subject metadata""" def __init__(self, sex: Sex, diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py index d5de10277..bce5df475 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py @@ -10,6 +10,9 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.nwb_writable_interface import \ + NwbWritableInterface from allensdk.internal.api import PostgresQueryMixin from allensdk.brain_observatory.behavior.data_objects import ( DataObject, StimulusTimestamps @@ -37,7 +40,7 @@ def from_lims_cache_key( ) -class RunningAcquisition(DataObject): +class RunningAcquisition(DataObject, NwbWritableInterface): """A DataObject which contains properties and methods to load, process, and represent running acquisition data. diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py index c3fe6bbe8..2bcfb79be 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py @@ -10,6 +10,9 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.nwb_writable_interface import \ + NwbWritableInterface from allensdk.core.exceptions import DataFrameIndexError from allensdk.internal.api import PostgresQueryMixin from allensdk.brain_observatory.behavior.data_objects import ( @@ -41,7 +44,7 @@ def from_lims_cache_key( ) -class RunningSpeed(DataObject): +class RunningSpeed(DataObject, NwbWritableInterface): """A DataObject which contains properties and methods to load, process, and represent running speed data. diff --git a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py index 0293c3ab2..c82a5794d 100644 --- a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py +++ b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py @@ -8,17 +8,20 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .stimulus_file_readable_mixin \ +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .stimulus_file_readable_interface \ import \ - StimulusFileReadableMixin -from allensdk.brain_observatory.behavior.data_objects._base.readable_mixins\ - .sync_file_readable_mixin import \ - SyncFileReadableMixin + StimulusFileReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ + .sync_file_readable_interface import \ + SyncFileReadableInterface from allensdk.brain_observatory.behavior.data_objects import DataObject from allensdk.brain_observatory.behavior.data_files import ( StimulusFile, SyncFile ) +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.nwb_writable_interface import \ + NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.stimulus_timestamps.timestamps_processing import ( # noqa: E501 get_behavior_stimulus_timestamps, get_ophys_stimulus_timestamps ) @@ -35,8 +38,8 @@ def from_lims_cache_key( return hashkey(behavior_session_id, ophys_experiment_id) -class StimulusTimestamps(DataObject, StimulusFileReadableMixin, - SyncFileReadableMixin): +class StimulusTimestamps(DataObject, StimulusFileReadableInterface, + SyncFileReadableInterface, NwbWritableInterface): """A DataObject which contains properties and methods to load, process, and represent visual behavior stimulus timestamp data. From a0fc2383d9168d6404fa32f0807ff98594fb3493 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 7 Jun 2021 14:32:54 -0700 Subject: [PATCH 024/234] Rename --- allensdk/brain_observatory/behavior/behavior_session.py | 6 +++--- ...readable_interface.py => internal_readable_interface.py} | 6 +++--- .../metadata/behavior_metadata/behavior_metadata.py | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) rename allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/{internal_mixed_readable_interface.py => internal_readable_interface.py} (71%) diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index 2fbfe987d..a453acb95 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -9,8 +9,8 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ - .internal_mixed_readable_interface import \ - InternalMixedReadableInterface + .internal_readable_interface import \ + InternalReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.nwb_writable_interface import \ NwbWritableInterface @@ -37,7 +37,7 @@ BehaviorDataApi = Type[BehaviorBase] -class BehaviorSession(DataObject, InternalMixedReadableInterface, +class BehaviorSession(DataObject, InternalReadableInterface, NwbWritableInterface, LazyPropertyMixin): def __init__( self, api: Optional[BehaviorDataApi] = None, diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/internal_mixed_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/internal_readable_interface.py similarity index 71% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/internal_mixed_readable_interface.py rename to allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/internal_readable_interface.py index 89e21d2dd..adaa6af61 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/internal_mixed_readable_interface.py +++ b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/internal_readable_interface.py @@ -3,13 +3,13 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject -class InternalMixedReadableInterface(abc.ABC): +class InternalReadableInterface(abc.ABC): """Marks a data object as readable from a variety of internal data sources """ @classmethod @abc.abstractmethod - def from_onprem(cls, *args) -> "DataObject": # pragma: no cover - """Populate a DataObject from various on-prem data sources + def from_internal(cls, *args) -> "DataObject": # pragma: no cover + """Populate a DataObject from various internal data sources Returns ------- diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index 4297a3f91..860b4c819 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -9,9 +9,9 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject, \ StimulusTimestamps, BehaviorSessionId from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ - .internal_mixed_readable_interface \ + .internal_readable_interface \ import \ - InternalMixedReadableInterface + InternalReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.writable_interfaces\ .nwb_writable_interface import \ NwbWritableInterface @@ -178,7 +178,7 @@ def get_task_parameters(data: Dict) -> Dict: return task_parameters -class BehaviorMetadata(DataObject, InternalMixedReadableInterface, +class BehaviorMetadata(DataObject, InternalReadableInterface, NwbWritableInterface): """Container class for behavior metadata""" def __init__(self, From 83b8a8163ba7f3798e3db8be1d580e14d328973c Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 7 Jun 2021 14:34:55 -0700 Subject: [PATCH 025/234] Move behavior ophys metadata --- .../ophys_experiment_metadata}/behavior_ophys_metadata.py | 0 allensdk/brain_observatory/behavior/metadata/__init__.py | 0 .../session_apis/abcs/session_base/behavior_ophys_base.py | 3 ++- .../behavior/session_apis/data_io/behavior_ophys_nwb_api.py | 3 ++- .../data_transforms/behavior_ophys_data_transforms.py | 3 ++- 5 files changed, 6 insertions(+), 3 deletions(-) rename allensdk/brain_observatory/behavior/{metadata => data_objects/metadata/ophys_experiment_metadata}/behavior_ophys_metadata.py (100%) delete mode 100644 allensdk/brain_observatory/behavior/metadata/__init__.py diff --git a/allensdk/brain_observatory/behavior/metadata/behavior_ophys_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/behavior_ophys_metadata.py similarity index 100% rename from allensdk/brain_observatory/behavior/metadata/behavior_ophys_metadata.py rename to allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/behavior_ophys_metadata.py diff --git a/allensdk/brain_observatory/behavior/metadata/__init__.py b/allensdk/brain_observatory/behavior/metadata/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_ophys_base.py b/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_ophys_base.py index 328f0c5df..108ee5ba4 100644 --- a/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_ophys_base.py +++ b/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_ophys_base.py @@ -4,7 +4,8 @@ import numpy as np import pandas as pd -from allensdk.brain_observatory.behavior.metadata.behavior_ophys_metadata \ +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.behavior_ophys_metadata \ import BehaviorOphysMetadata from allensdk.brain_observatory.behavior.session_apis.abcs.\ session_base.behavior_base import BehaviorBase diff --git a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py index def0cfe3c..4d5f31e47 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py @@ -11,7 +11,8 @@ from pynwb import NWBHDF5IO, NWBFile -from allensdk.brain_observatory.behavior.metadata.behavior_ophys_metadata \ +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.behavior_ophys_metadata \ import BehaviorOphysMetadata from allensdk.brain_observatory.behavior.event_detection import \ filter_events_array diff --git a/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py b/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py index 23c7885dc..d038d42ee 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py @@ -11,7 +11,8 @@ import warnings from allensdk.api.warehouse_cache.cache import memoize -from allensdk.brain_observatory.behavior.metadata.behavior_ophys_metadata \ +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.behavior_ophys_metadata \ import BehaviorOphysMetadata from allensdk.brain_observatory.behavior.event_detection import \ filter_events_array From 5c2b2ed186e2e1f52152494ee81b10cbfcf3236b Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 7 Jun 2021 14:47:51 -0700 Subject: [PATCH 026/234] Clean up missing interfaces --- .../metadata/behavior_metadata/behavior_session_id.py | 6 +++++- .../metadata/behavior_metadata/behavior_session_uuid.py | 6 +++++- .../metadata/behavior_metadata/date_of_acquisition.py | 9 ++++++++- .../metadata/behavior_metadata/equipment_name.py | 8 +++++++- .../metadata/behavior_metadata/foraging_id.py | 5 ++++- .../metadata/behavior_metadata/session_type.py | 8 -------- .../data_objects/metadata/subject_metadata/age.py | 8 +++++++- .../metadata/subject_metadata/driver_line.py | 5 ++++- .../metadata/subject_metadata/full_genotype.py | 5 ++++- .../data_objects/metadata/subject_metadata/mouse_id.py | 5 ++++- .../metadata/subject_metadata/reporter_line.py | 5 ++++- .../data_objects/metadata/subject_metadata/sex.py | 5 ++++- 12 files changed, 56 insertions(+), 19 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py index 244d76e45..69a0c0cbc 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py @@ -3,6 +3,9 @@ from cachetools import cached, LRUCache from cachetools.keys import hashkey +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface @@ -14,7 +17,8 @@ def from_lims_cache_key(cls, db, ophys_experiment_id: int): return hashkey(ophys_experiment_id) -class BehaviorSessionId(DataObject, LimsReadableInterface): +class BehaviorSessionId(DataObject, LimsReadableInterface, + JsonReadableInterface): def __init__(self, behavior_session_id: int): super().__init__(name="behavior_session_id", value=behavior_session_id) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py index 9ba0155f3..279a5fd68 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py @@ -5,12 +5,16 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .stimulus_file_readable_interface import \ StimulusFileReadableInterface -class BehaviorSessionUUID(DataObject, StimulusFileReadableInterface): +class BehaviorSessionUUID(DataObject, StimulusFileReadableInterface, + JsonReadableInterface): """the universally unique identifier (UUID)""" def __init__(self, behavior_session_uuid: Optional[uuid.UUID]): super().__init__(name="behavior_session_uuid", value=behavior_session_uuid) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py index cbf269673..2aee3dc89 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py @@ -6,17 +6,24 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin -class DateOfAcquisition(DataObject, LimsReadableInterface): +class DateOfAcquisition(DataObject, LimsReadableInterface, + JsonReadableInterface): """timestamp for when experiment was started in UTC""" def __init__(self, date_of_acquisition: float): super().__init__(name="date_of_acquisition", value=date_of_acquisition) + def from_json(cls, dict_repr: dict) -> "DateOfAcquisition": + pass + def to_json(self) -> dict: return {"stimulus_frame_rate": self.value} diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py index b3d92464c..6973a0612 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py @@ -1,10 +1,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin -class EquipmentName(DataObject): +class EquipmentName(DataObject, JsonReadableInterface, LimsReadableInterface): """the name of the experimental rig.""" def __init__(self, equipment_name: str): super().__init__(name="equipment_name", value=equipment_name) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py index 9ea841b11..8daa27d65 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py @@ -3,13 +3,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin -class ForagingId(DataObject, LimsReadableInterface): +class ForagingId(DataObject, LimsReadableInterface, JsonReadableInterface): """Foraging id""" def __init__(self, foraging_id: uuid.UUID): super().__init__(name="foraging_id", value=foraging_id) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py index 25d08d62c..b0607882a 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py @@ -13,17 +13,9 @@ class SessionType(DataObject, StimulusFileReadableInterface): def __init__(self, session_type: str): super().__init__(name="session_type", value=session_type) - @classmethod - def from_json(cls, dict_repr: dict) -> None: - raise NotImplementedError() - def to_json(self) -> dict: return {"sex": self.value} - @classmethod - def from_lims(cls) -> None: - raise NotImplementedError() - @classmethod def from_stimulus_file( cls, diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py index 8c0849d59..ec734070f 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py @@ -5,10 +5,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin -class Age(DataObject): +class Age(DataObject, JsonReadableInterface, LimsReadableInterface): """Age of animal (in days)""" def __init__(self, age: int): super().__init__(name="age_in_days", value=age) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py index b2124652a..391320a12 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py @@ -3,6 +3,9 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface @@ -10,7 +13,7 @@ OneOrMoreResultExpectedError -class DriverLine(DataObject, LimsReadableInterface): +class DriverLine(DataObject, LimsReadableInterface, JsonReadableInterface): """the genotype name(s) of the driver line(s)""" def __init__(self, driver_line: List[str]): super().__init__(name="driver_line", value=driver_line) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py index ac42044a2..664826624 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py @@ -4,13 +4,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin -class FullGenotype(DataObject, LimsReadableInterface): +class FullGenotype(DataObject, LimsReadableInterface, JsonReadableInterface): """the name of the subject's genotype""" def __init__(self, full_genotype: str): super().__init__(name="full_genotype", value=full_genotype) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py index 4aa00e213..be8fe6ea9 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py @@ -1,13 +1,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin -class MouseId(DataObject, LimsReadableInterface): +class MouseId(DataObject, LimsReadableInterface, JsonReadableInterface): """the LabTracks ID""" def __init__(self, mouse_id: int): super().__init__(name="mouse_id", value=mouse_id) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py index a56b8fb70..fc21e5375 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py @@ -4,6 +4,9 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface @@ -11,7 +14,7 @@ OneOrMoreResultExpectedError -class ReporterLine(DataObject, LimsReadableInterface): +class ReporterLine(DataObject, LimsReadableInterface, JsonReadableInterface): """the genotype name(s) of the reporter line(s)""" def __init__(self, reporter_line: Optional[str]): super().__init__(name="reporter_line", value=reporter_line) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py index d48076d89..01640df9e 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py @@ -1,13 +1,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin -class Sex(DataObject, LimsReadableInterface): +class Sex(DataObject, LimsReadableInterface, JsonReadableInterface): """sex of the animal (M/F)""" def __init__(self, sex: str): super().__init__(name="sex", value=sex) From ae86c52564c28b946b24d6860a3baf79f30d4d8b Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 7 Jun 2021 15:25:00 -0700 Subject: [PATCH 027/234] adds json writable interface --- .../behavior/behavior_session.py | 15 +++++++++---- .../data_objects/_base/_data_object_abc.py | 13 ------------ .../json_writable_interface.py | 21 +++++++++++++++++++ .../behavior_metadata/behavior_metadata.py | 10 ++++++++- .../behavior_metadata/behavior_session_id.py | 6 +++++- .../behavior_session_uuid.py | 13 +----------- .../behavior_metadata/date_of_acquisition.py | 5 ++++- .../behavior_metadata/equipment_name.py | 6 +++++- .../metadata/behavior_metadata/foraging_id.py | 8 +++++-- .../behavior_metadata/session_type.py | 3 --- .../behavior_metadata/stimulus_frame_rate.py | 3 --- .../metadata/subject_metadata/age.py | 6 +++++- .../metadata/subject_metadata/driver_line.py | 6 +++++- .../subject_metadata/full_genotype.py | 6 +++++- .../metadata/subject_metadata/mouse_id.py | 9 ++++++-- .../subject_metadata/reporter_line.py | 6 +++++- .../metadata/subject_metadata/sex.py | 6 +++++- .../subject_metadata/subject_metadata.py | 5 ++++- .../running_speed/running_acquisition.py | 9 +++++++- .../running_speed/running_speed.py | 12 ++++++++++- .../stimulus_timestamps.py | 6 +++++- 21 files changed, 122 insertions(+), 52 deletions(-) create mode 100644 allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/json_writable_interface.py diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index a453acb95..ab654134f 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -11,6 +11,12 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .internal_readable_interface import \ InternalReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.nwb_writable_interface import \ NwbWritableInterface @@ -38,7 +44,9 @@ class BehaviorSession(DataObject, InternalReadableInterface, - NwbWritableInterface, LazyPropertyMixin): + JsonReadableInterface, NwbWritableInterface, + JsonWritableInterface, + LazyPropertyMixin): def __init__( self, api: Optional[BehaviorDataApi] = None, behavior_session_id: BehaviorSessionId = None, @@ -93,8 +101,7 @@ def from_json(cls, session_data: dict) -> "BehaviorSession": ) @classmethod - def from_internal_mixed(cls, - behavior_session_id: int) -> "BehaviorSession": + def from_internal(cls, behavior_session_id: int) -> "BehaviorSession": lims_db = db_connection_creator( fallback_credentials=LIMS_DB_CREDENTIAL_MAP ) @@ -114,7 +121,7 @@ def from_internal_mixed(cls, running_speed = RunningSpeed.from_lims( lims_db, behavior_session_id.value ) - behavior_metadata = BehaviorMetadata.from_internal_mixed( + behavior_metadata = BehaviorMetadata.from_internal( behavior_session_id=behavior_session_id, lims_db=lims_db, stimulus_file=stimulus_file, stimulus_timestamps=stimulus_timestamps diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py index 887a7a151..ef39db854 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py @@ -24,19 +24,6 @@ def name(self) -> str: def value(self) -> Any: return self._value - @abc.abstractmethod - def to_json(self) -> dict: # pragma: no cover - """Given an already populated DataObject, return the dict that - when used with the `from_json()` classmethod would produce the same - DataObject - - Returns - ------- - dict: - The JSON (in dict form) that would produce the DataObject. - """ - raise NotImplementedError() - @classmethod @abc.abstractmethod def from_nwb(cls, nwbfile: NWBFile) -> "DataObject": # pragma: no cover diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/json_writable_interface.py b/allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/json_writable_interface.py new file mode 100644 index 000000000..6b50b4f83 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/json_writable_interface.py @@ -0,0 +1,21 @@ +import abc + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject + + +class JsonWritableInterface(abc.ABC): + """Marks a data object as writable to NWB""" + @abc.abstractmethod + def to_json(self) -> dict: # pragma: no cover + """Given an already populated DataObject, return the dict that + when used with the `from_json()` classmethod would produce the same + DataObject + + Returns + ------- + dict: + The JSON (in dict form) that would produce the DataObject. + """ + raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index 860b4c819..1b72e17ca 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -12,6 +12,12 @@ .internal_readable_interface \ import \ InternalReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.brain_observatory.behavior.data_objects._base.writable_interfaces\ .nwb_writable_interface import \ NwbWritableInterface @@ -179,6 +185,8 @@ def get_task_parameters(data: Dict) -> Dict: class BehaviorMetadata(DataObject, InternalReadableInterface, + JsonReadableInterface, + JsonWritableInterface, NwbWritableInterface): """Container class for behavior metadata""" def __init__(self, @@ -199,7 +207,7 @@ def __init__(self, self._exclude_from_equals = set() @classmethod - def from_internal_mixed( + def from_internal( cls, behavior_session_id: BehaviorSessionId, stimulus_file: StimulusFile, diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py index 69a0c0cbc..17f08856a 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py @@ -9,6 +9,9 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin from allensdk.brain_observatory.behavior.data_objects import DataObject @@ -18,7 +21,8 @@ def from_lims_cache_key(cls, db, ophys_experiment_id: int): class BehaviorSessionId(DataObject, LimsReadableInterface, - JsonReadableInterface): + JsonReadableInterface, + JsonWritableInterface): def __init__(self, behavior_session_id: int): super().__init__(name="behavior_session_id", value=behavior_session_id) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py index 279a5fd68..892463bff 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py @@ -5,27 +5,16 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .stimulus_file_readable_interface import \ StimulusFileReadableInterface -class BehaviorSessionUUID(DataObject, StimulusFileReadableInterface, - JsonReadableInterface): +class BehaviorSessionUUID(DataObject, StimulusFileReadableInterface): """the universally unique identifier (UUID)""" def __init__(self, behavior_session_uuid: Optional[uuid.UUID]): super().__init__(name="behavior_session_uuid", value=behavior_session_uuid) - @classmethod - def from_json(cls, dict_repr: dict) -> "BehaviorSessionUUID": - pass - - def to_json(self) -> dict: - return {"sex": self.value} - @classmethod def from_stimulus_file( cls, stimulus_file: StimulusFile) -> "BehaviorSessionUUID": diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py index 2aee3dc89..f1fc1ccd9 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py @@ -12,11 +12,14 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin class DateOfAcquisition(DataObject, LimsReadableInterface, - JsonReadableInterface): + JsonReadableInterface, JsonWritableInterface): """timestamp for when experiment was started in UTC""" def __init__(self, date_of_acquisition: float): super().__init__(name="date_of_acquisition", value=date_of_acquisition) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py index 6973a0612..4e20ec40a 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py @@ -7,10 +7,14 @@ from allensdk.brain_observatory.behavior.data_objects._base\ .readable_interfaces.lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin -class EquipmentName(DataObject, JsonReadableInterface, LimsReadableInterface): +class EquipmentName(DataObject, JsonReadableInterface, LimsReadableInterface, + JsonWritableInterface): """the name of the experimental rig.""" def __init__(self, equipment_name: str): super().__init__(name="equipment_name", value=equipment_name) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py index 8daa27d65..2f007a781 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py @@ -9,10 +9,14 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin -class ForagingId(DataObject, LimsReadableInterface, JsonReadableInterface): +class ForagingId(DataObject, LimsReadableInterface, JsonReadableInterface, + JsonWritableInterface): """Foraging id""" def __init__(self, foraging_id: uuid.UUID): super().__init__(name="foraging_id", value=foraging_id) @@ -41,4 +45,4 @@ def from_lims(cls, behavior_session_id: int, @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "ForagingId": - pass + raise NotImplementedError('Foraging id is not stored in NWB') diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py index b0607882a..d9b1f2832 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py @@ -13,9 +13,6 @@ class SessionType(DataObject, StimulusFileReadableInterface): def __init__(self, session_type: str): super().__init__(name="session_type", value=session_type) - def to_json(self) -> dict: - return {"sex": self.value} - @classmethod def from_stimulus_file( cls, diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py index 669268dfc..37c11bac5 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py @@ -13,9 +13,6 @@ class StimulusFrameRate(DataObject, StimulusFileReadableInterface): def __init__(self, stimulus_frame_rate: float): super().__init__(name="stimulus_frame_rate", value=stimulus_frame_rate) - def to_json(self) -> dict: - return {"stimulus_frame_rate": self.value} - @classmethod def from_stimulus_file( cls, diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py index ec734070f..b221c866e 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py @@ -11,10 +11,14 @@ from allensdk.brain_observatory.behavior.data_objects._base\ .readable_interfaces.lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin -class Age(DataObject, JsonReadableInterface, LimsReadableInterface): +class Age(DataObject, JsonReadableInterface, LimsReadableInterface, + JsonWritableInterface): """Age of animal (in days)""" def __init__(self, age: int): super().__init__(name="age_in_days", value=age) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py index 391320a12..1cd951fc9 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py @@ -9,11 +9,15 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin, \ OneOrMoreResultExpectedError -class DriverLine(DataObject, LimsReadableInterface, JsonReadableInterface): +class DriverLine(DataObject, LimsReadableInterface, JsonReadableInterface, + JsonWritableInterface): """the genotype name(s) of the driver line(s)""" def __init__(self, driver_line: List[str]): super().__init__(name="driver_line", value=driver_line) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py index 664826624..0b983ac24 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py @@ -10,10 +10,14 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin -class FullGenotype(DataObject, LimsReadableInterface, JsonReadableInterface): +class FullGenotype(DataObject, LimsReadableInterface, JsonReadableInterface, + JsonWritableInterface): """the name of the subject's genotype""" def __init__(self, full_genotype: str): super().__init__(name="full_genotype", value=full_genotype) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py index be8fe6ea9..abca3a870 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py @@ -7,17 +7,22 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin -class MouseId(DataObject, LimsReadableInterface, JsonReadableInterface): +class MouseId(DataObject, LimsReadableInterface, JsonReadableInterface, + JsonWritableInterface): """the LabTracks ID""" def __init__(self, mouse_id: int): super().__init__(name="mouse_id", value=mouse_id) @classmethod def from_json(cls, dict_repr: dict) -> "MouseId": - pass + mouse_id = dict_repr['external_specimen_name'] + return cls(mouse_id=mouse_id) def to_json(self) -> dict: return {"sex": self.value} diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py index fc21e5375..97560dd77 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py @@ -10,11 +10,15 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin, \ OneOrMoreResultExpectedError -class ReporterLine(DataObject, LimsReadableInterface, JsonReadableInterface): +class ReporterLine(DataObject, LimsReadableInterface, JsonReadableInterface, + JsonWritableInterface): """the genotype name(s) of the reporter line(s)""" def __init__(self, reporter_line: Optional[str]): super().__init__(name="reporter_line", value=reporter_line) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py index 01640df9e..134f284bd 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py @@ -7,10 +7,14 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin -class Sex(DataObject, LimsReadableInterface, JsonReadableInterface): +class Sex(DataObject, LimsReadableInterface, JsonReadableInterface, + JsonWritableInterface): """sex of the animal (M/F)""" def __init__(self, sex: str): super().__init__(name="sex", value=sex) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py index b7a75d524..a33e7ca39 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py @@ -7,6 +7,9 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.brain_observatory.behavior.data_objects._base.writable_interfaces\ .nwb_writable_interface import \ NwbWritableInterface @@ -34,7 +37,7 @@ class SubjectMetadata(DataObject, LimsReadableInterface, - NwbWritableInterface): + NwbWritableInterface, JsonWritableInterface): """Subject metadata""" def __init__(self, sex: Sex, diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py index bce5df475..5a5bb9a22 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py @@ -10,6 +10,12 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.nwb_writable_interface import \ NwbWritableInterface @@ -40,7 +46,8 @@ def from_lims_cache_key( ) -class RunningAcquisition(DataObject, NwbWritableInterface): +class RunningAcquisition(DataObject, LimsReadableInterface, + NwbWritableInterface, JsonWritableInterface): """A DataObject which contains properties and methods to load, process, and represent running acquisition data. diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py index 2bcfb79be..51ab2c793 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py @@ -10,6 +10,15 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.nwb_writable_interface import \ NwbWritableInterface @@ -44,7 +53,8 @@ def from_lims_cache_key( ) -class RunningSpeed(DataObject, NwbWritableInterface): +class RunningSpeed(DataObject, LimsReadableInterface, NwbWritableInterface, + JsonReadableInterface, JsonWritableInterface): """A DataObject which contains properties and methods to load, process, and represent running speed data. diff --git a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py index c82a5794d..f6dc5470d 100644 --- a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py +++ b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py @@ -19,6 +19,9 @@ from allensdk.brain_observatory.behavior.data_files import ( StimulusFile, SyncFile ) +from allensdk.brain_observatory.behavior.data_objects._base\ + .writable_interfaces.json_writable_interface import \ + JsonWritableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.nwb_writable_interface import \ NwbWritableInterface @@ -39,7 +42,8 @@ def from_lims_cache_key( class StimulusTimestamps(DataObject, StimulusFileReadableInterface, - SyncFileReadableInterface, NwbWritableInterface): + SyncFileReadableInterface, NwbWritableInterface, + JsonWritableInterface): """A DataObject which contains properties and methods to load, process, and represent visual behavior stimulus timestamp data. From 3b94dd81a475d9f5557c60b2a48937b342e62b28 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 8 Jun 2021 07:47:53 -0700 Subject: [PATCH 028/234] make api conform to from_nwb api --- .../behavior/behavior_session.py | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index ab654134f..f19e104ac 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -137,18 +137,14 @@ def from_internal(cls, behavior_session_id: int) -> "BehaviorSession": ) @classmethod - def from_nwb( - cls, nwb_path: str, **api_kwargs: Any - ) -> "BehaviorSession": - with pynwb.NWBHDF5IO(str(nwb_path), 'r') as read_io: - nwbfile = read_io.read() - behavior_session_id = BehaviorSessionId.from_nwb(nwbfile) - stimulus_timestamps = StimulusTimestamps.from_nwb(nwbfile) - running_acquisition = RunningAcquisition.from_nwb(nwbfile) - raw_running_speed = RunningSpeed.from_nwb(nwbfile, filtered=False) - running_speed = RunningSpeed.from_nwb(nwbfile) + def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorSession": + behavior_session_id = BehaviorSessionId.from_nwb(nwbfile) + stimulus_timestamps = StimulusTimestamps.from_nwb(nwbfile) + running_acquisition = RunningAcquisition.from_nwb(nwbfile) + raw_running_speed = RunningSpeed.from_nwb(nwbfile, filtered=False) + running_speed = RunningSpeed.from_nwb(nwbfile) + return cls( - api=BehaviorNwbApi.from_path(path=nwb_path, **api_kwargs), behavior_session_id=behavior_session_id, stimulus_timestamps=stimulus_timestamps, running_acquisition=running_acquisition, @@ -156,6 +152,12 @@ def from_nwb( running_speed=running_speed ) + @classmethod + def from_nwb_path(cls, nwb_path: str): + with pynwb.NWBHDF5IO(str(nwb_path), 'r') as read_io: + nwbfile = read_io.read() + return cls.from_nwb(nwbfile=nwbfile) + def to_json(self) -> dict: pass From 18de5d494b40f54a420a87adb30e0687ffe6d2c6 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 8 Jun 2021 11:46:58 -0700 Subject: [PATCH 029/234] Adds nwb readable interface --- .../behavior/behavior_session.py | 4 +++ .../data_objects/_base/_data_object_abc.py | 17 ------------- .../nwb_readable_interface.py | 25 +++++++++++++++++++ .../behavior_metadata/behavior_metadata.py | 4 +++ .../behavior_metadata/behavior_session_id.py | 4 +++ .../behavior_session_uuid.py | 6 ++++- .../behavior_metadata/date_of_acquisition.py | 6 ++++- .../behavior_metadata/equipment_name.py | 5 +++- .../metadata/behavior_metadata/foraging_id.py | 4 --- .../behavior_metadata/session_type.py | 6 ++++- .../behavior_metadata/stimulus_frame_rate.py | 6 ++++- .../metadata/subject_metadata/age.py | 5 +++- .../metadata/subject_metadata/driver_line.py | 5 +++- .../subject_metadata/full_genotype.py | 5 +++- .../metadata/subject_metadata/mouse_id.py | 5 +++- .../subject_metadata/reporter_line.py | 5 +++- .../metadata/subject_metadata/sex.py | 5 +++- .../subject_metadata/subject_metadata.py | 5 +++- .../running_speed/running_acquisition.py | 6 ++++- .../running_speed/running_speed.py | 8 ++++-- .../stimulus_timestamps.py | 7 ++++-- 21 files changed, 105 insertions(+), 38 deletions(-) create mode 100644 allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/nwb_readable_interface.py diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index f19e104ac..9e098ec7b 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -14,6 +14,9 @@ from allensdk.brain_observatory.behavior.data_objects._base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -44,6 +47,7 @@ class BehaviorSession(DataObject, InternalReadableInterface, + NwbReadableInterface, JsonReadableInterface, NwbWritableInterface, JsonWritableInterface, LazyPropertyMixin): diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py index ef39db854..a411e52e5 100644 --- a/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py @@ -23,20 +23,3 @@ def name(self) -> str: @property def value(self) -> Any: return self._value - - @classmethod - @abc.abstractmethod - def from_nwb(cls, nwbfile: NWBFile) -> "DataObject": # pragma: no cover - """Populate a DataObject from a pyNWB file object. - - Parameters - ---------- - nwbfile: - The file object (NWBFile) of a pynwb dataset file. - - Returns - ------- - DataObject: - An instantiated DataObject which has `name` and `value` properties - """ - raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/nwb_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/nwb_readable_interface.py new file mode 100644 index 000000000..4f38b38c9 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/nwb_readable_interface.py @@ -0,0 +1,25 @@ +import abc + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject + + +class NwbReadableInterface(abc.ABC): + """Marks a data object as readable from NWB""" + @classmethod + @abc.abstractmethod + def from_nwb(cls, nwbfile: NWBFile) -> "DataObject": # pragma: no cover + """Populate a DataObject from a pyNWB file object. + + Parameters + ---------- + nwbfile: + The file object (NWBFile) of a pynwb dataset file. + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index 1b72e17ca..fa539231c 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -15,6 +15,9 @@ from allensdk.brain_observatory.behavior.data_objects._base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -186,6 +189,7 @@ def get_task_parameters(data: Dict) -> Dict: class BehaviorMetadata(DataObject, InternalReadableInterface, JsonReadableInterface, + NwbReadableInterface, JsonWritableInterface, NwbWritableInterface): """Container class for behavior metadata""" diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py index 17f08856a..b58048724 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py @@ -9,6 +9,9 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -22,6 +25,7 @@ def from_lims_cache_key(cls, db, ophys_experiment_id: int): class BehaviorSessionId(DataObject, LimsReadableInterface, JsonReadableInterface, + NwbReadableInterface, JsonWritableInterface): def __init__(self, behavior_session_id: int): super().__init__(name="behavior_session_id", value=behavior_session_id) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py index 892463bff..32c63af95 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py @@ -5,12 +5,16 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .stimulus_file_readable_interface import \ StimulusFileReadableInterface -class BehaviorSessionUUID(DataObject, StimulusFileReadableInterface): +class BehaviorSessionUUID(DataObject, StimulusFileReadableInterface, + NwbReadableInterface): """the universally unique identifier (UUID)""" def __init__(self, behavior_session_uuid: Optional[uuid.UUID]): super().__init__(name="behavior_session_uuid", value=behavior_session_uuid) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py index f1fc1ccd9..a91f524c3 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py @@ -12,6 +12,9 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -19,7 +22,8 @@ class DateOfAcquisition(DataObject, LimsReadableInterface, - JsonReadableInterface, JsonWritableInterface): + JsonReadableInterface, NwbReadableInterface, + JsonWritableInterface): """timestamp for when experiment was started in UTC""" def __init__(self, date_of_acquisition: float): super().__init__(name="date_of_acquisition", value=date_of_acquisition) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py index 4e20ec40a..b4690c868 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py @@ -7,6 +7,9 @@ from allensdk.brain_observatory.behavior.data_objects._base\ .readable_interfaces.lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -14,7 +17,7 @@ class EquipmentName(DataObject, JsonReadableInterface, LimsReadableInterface, - JsonWritableInterface): + NwbReadableInterface, JsonWritableInterface): """the name of the experimental rig.""" def __init__(self, equipment_name: str): super().__init__(name="equipment_name", value=equipment_name) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py index 2f007a781..b2d38f656 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py @@ -42,7 +42,3 @@ def from_lims(cls, behavior_session_id: int, foraging_id = lims_db.fetchone(query, strict=True) foraging_id = uuid.UUID(foraging_id) return cls(foraging_id=foraging_id) - - @classmethod - def from_nwb(cls, nwbfile: NWBFile) -> "ForagingId": - raise NotImplementedError('Foraging id is not stored in NWB') diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py index d9b1f2832..fdace9a50 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py @@ -2,13 +2,17 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .stimulus_file_readable_interface \ import \ StimulusFileReadableInterface -class SessionType(DataObject, StimulusFileReadableInterface): +class SessionType(DataObject, StimulusFileReadableInterface, + NwbReadableInterface): """the stimulus set used""" def __init__(self, session_type: str): super().__init__(name="session_type", value=session_type) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py index 37c11bac5..f44bcd2c5 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py @@ -2,13 +2,17 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject, \ StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .stimulus_file_readable_interface \ import \ StimulusFileReadableInterface -class StimulusFrameRate(DataObject, StimulusFileReadableInterface): +class StimulusFrameRate(DataObject, StimulusFileReadableInterface, + NwbReadableInterface): """Stimulus frame rate""" def __init__(self, stimulus_frame_rate: float): super().__init__(name="stimulus_frame_rate", value=stimulus_frame_rate) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py index b221c866e..7439b25c0 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py @@ -11,6 +11,9 @@ from allensdk.brain_observatory.behavior.data_objects._base\ .readable_interfaces.lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -18,7 +21,7 @@ class Age(DataObject, JsonReadableInterface, LimsReadableInterface, - JsonWritableInterface): + NwbReadableInterface, JsonWritableInterface): """Age of animal (in days)""" def __init__(self, age: int): super().__init__(name="age_in_days", value=age) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py index 1cd951fc9..a0cde264c 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py @@ -9,6 +9,9 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -17,7 +20,7 @@ class DriverLine(DataObject, LimsReadableInterface, JsonReadableInterface, - JsonWritableInterface): + NwbReadableInterface, JsonWritableInterface): """the genotype name(s) of the driver line(s)""" def __init__(self, driver_line: List[str]): super().__init__(name="driver_line", value=driver_line) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py index 0b983ac24..ce29051cf 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py @@ -10,6 +10,9 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -17,7 +20,7 @@ class FullGenotype(DataObject, LimsReadableInterface, JsonReadableInterface, - JsonWritableInterface): + NwbReadableInterface, JsonWritableInterface): """the name of the subject's genotype""" def __init__(self, full_genotype: str): super().__init__(name="full_genotype", value=full_genotype) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py index abca3a870..f22a355ec 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py @@ -7,6 +7,9 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -14,7 +17,7 @@ class MouseId(DataObject, LimsReadableInterface, JsonReadableInterface, - JsonWritableInterface): + NwbReadableInterface, JsonWritableInterface): """the LabTracks ID""" def __init__(self, mouse_id: int): super().__init__(name="mouse_id", value=mouse_id) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py index 97560dd77..ae9800ed3 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py @@ -10,6 +10,9 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -18,7 +21,7 @@ class ReporterLine(DataObject, LimsReadableInterface, JsonReadableInterface, - JsonWritableInterface): + NwbReadableInterface, JsonWritableInterface): """the genotype name(s) of the reporter line(s)""" def __init__(self, reporter_line: Optional[str]): super().__init__(name="reporter_line", value=reporter_line) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py index 134f284bd..d1df49220 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py @@ -7,6 +7,9 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -14,7 +17,7 @@ class Sex(DataObject, LimsReadableInterface, JsonReadableInterface, - JsonWritableInterface): + NwbReadableInterface, JsonWritableInterface): """sex of the animal (M/F)""" def __init__(self, sex: str): super().__init__(name="sex", value=sex) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py index a33e7ca39..99b479508 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py @@ -7,6 +7,9 @@ from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -36,7 +39,7 @@ from allensdk.internal.api import PostgresQueryMixin -class SubjectMetadata(DataObject, LimsReadableInterface, +class SubjectMetadata(DataObject, LimsReadableInterface, NwbReadableInterface, NwbWritableInterface, JsonWritableInterface): """Subject metadata""" def __init__(self, diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py index 5a5bb9a22..59ed6e128 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py @@ -13,6 +13,9 @@ from allensdk.brain_observatory.behavior.data_objects._base\ .readable_interfaces.lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -47,7 +50,8 @@ def from_lims_cache_key( class RunningAcquisition(DataObject, LimsReadableInterface, - NwbWritableInterface, JsonWritableInterface): + NwbReadableInterface, NwbWritableInterface, + JsonWritableInterface): """A DataObject which contains properties and methods to load, process, and represent running acquisition data. diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py index 51ab2c793..6afca1e36 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py @@ -16,6 +16,9 @@ from allensdk.brain_observatory.behavior.data_objects._base\ .readable_interfaces.lims_readable_interface import \ LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface @@ -53,8 +56,9 @@ def from_lims_cache_key( ) -class RunningSpeed(DataObject, LimsReadableInterface, NwbWritableInterface, - JsonReadableInterface, JsonWritableInterface): +class RunningSpeed(DataObject, LimsReadableInterface, NwbReadableInterface, + NwbWritableInterface, JsonReadableInterface, + JsonWritableInterface): """A DataObject which contains properties and methods to load, process, and represent running speed data. diff --git a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py index f6dc5470d..f64391213 100644 --- a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py +++ b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py @@ -8,6 +8,9 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries +from allensdk.brain_observatory.behavior.data_objects._base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ .stimulus_file_readable_interface \ import \ @@ -42,8 +45,8 @@ def from_lims_cache_key( class StimulusTimestamps(DataObject, StimulusFileReadableInterface, - SyncFileReadableInterface, NwbWritableInterface, - JsonWritableInterface): + SyncFileReadableInterface, NwbReadableInterface, + NwbWritableInterface, JsonWritableInterface): """A DataObject which contains properties and methods to load, process, and represent visual behavior stimulus timestamp data. From 37007059d9d4fa6dc091139c5562dcbd622b54d8 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 8 Jun 2021 11:49:24 -0700 Subject: [PATCH 030/234] rename _base package to base. shouldn't be protected --- .../brain_observatory/behavior/behavior_session.py | 10 +++++----- .../behavior/data_objects/__init__.py | 2 +- .../behavior/data_objects/{_base => base}/__init__.py | 0 .../data_objects/{_base => base}/_data_object_abc.py | 0 .../{_base => base}/readable_interfaces/__init__.py | 0 .../readable_interfaces/internal_readable_interface.py | 0 .../readable_interfaces/json_readable_interface.py | 0 .../readable_interfaces/lims_readable_interface.py | 0 .../readable_interfaces/nwb_readable_interface.py | 0 .../stimulus_file_readable_interface.py | 0 .../sync_file_readable_interface.py | 0 .../{_base => base}/writable_interfaces/__init__.py | 0 .../writable_interfaces/json_writable_interface.py | 0 .../writable_interfaces/nwb_writable_interface.py | 0 .../metadata/behavior_metadata/behavior_metadata.py | 10 +++++----- .../metadata/behavior_metadata/behavior_session_id.py | 8 ++++---- .../behavior_metadata/behavior_session_uuid.py | 4 ++-- .../metadata/behavior_metadata/date_of_acquisition.py | 8 ++++---- .../metadata/behavior_metadata/equipment_name.py | 8 ++++---- .../metadata/behavior_metadata/foraging_id.py | 6 +++--- .../metadata/behavior_metadata/session_type.py | 4 ++-- .../metadata/behavior_metadata/stimulus_frame_rate.py | 4 ++-- .../data_objects/metadata/subject_metadata/age.py | 8 ++++---- .../metadata/subject_metadata/driver_line.py | 8 ++++---- .../metadata/subject_metadata/full_genotype.py | 8 ++++---- .../data_objects/metadata/subject_metadata/mouse_id.py | 8 ++++---- .../metadata/subject_metadata/reporter_line.py | 8 ++++---- .../data_objects/metadata/subject_metadata/sex.py | 8 ++++---- .../metadata/subject_metadata/subject_metadata.py | 8 ++++---- .../data_objects/running_speed/running_acquisition.py | 8 ++++---- .../data_objects/running_speed/running_speed.py | 10 +++++----- .../stimulus_timestamps/stimulus_timestamps.py | 10 +++++----- 32 files changed, 74 insertions(+), 74 deletions(-) rename allensdk/brain_observatory/behavior/data_objects/{_base => base}/__init__.py (100%) rename allensdk/brain_observatory/behavior/data_objects/{_base => base}/_data_object_abc.py (100%) rename allensdk/brain_observatory/behavior/data_objects/{_base => base}/readable_interfaces/__init__.py (100%) rename allensdk/brain_observatory/behavior/data_objects/{_base => base}/readable_interfaces/internal_readable_interface.py (100%) rename allensdk/brain_observatory/behavior/data_objects/{_base => base}/readable_interfaces/json_readable_interface.py (100%) rename allensdk/brain_observatory/behavior/data_objects/{_base => base}/readable_interfaces/lims_readable_interface.py (100%) rename allensdk/brain_observatory/behavior/data_objects/{_base => base}/readable_interfaces/nwb_readable_interface.py (100%) rename allensdk/brain_observatory/behavior/data_objects/{_base => base}/readable_interfaces/stimulus_file_readable_interface.py (100%) rename allensdk/brain_observatory/behavior/data_objects/{_base => base}/readable_interfaces/sync_file_readable_interface.py (100%) rename allensdk/brain_observatory/behavior/data_objects/{_base => base}/writable_interfaces/__init__.py (100%) rename allensdk/brain_observatory/behavior/data_objects/{_base => base}/writable_interfaces/json_writable_interface.py (100%) rename allensdk/brain_observatory/behavior/data_objects/{_base => base}/writable_interfaces/nwb_writable_interface.py (100%) diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index 9e098ec7b..1aab97c1a 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -8,19 +8,19 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_files import StimulusFile -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .internal_readable_interface import \ InternalReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.nwb_writable_interface import \ NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ diff --git a/allensdk/brain_observatory/behavior/data_objects/__init__.py b/allensdk/brain_observatory/behavior/data_objects/__init__.py index 088722aec..b9a92a00d 100644 --- a/allensdk/brain_observatory/behavior/data_objects/__init__.py +++ b/allensdk/brain_observatory/behavior/data_objects/__init__.py @@ -1,4 +1,4 @@ -from allensdk.brain_observatory.behavior.data_objects._base._data_object_abc import DataObject # noqa: E501, F401 +from allensdk.brain_observatory.behavior.data_objects.base._data_object_abc import DataObject # noqa: E501, F401 from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_session_id import BehaviorSessionId # noqa: E501, F401 from allensdk.brain_observatory.behavior.data_objects.stimulus_timestamps.stimulus_timestamps import StimulusTimestamps # noqa: E501, F401 diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/__init__.py b/allensdk/brain_observatory/behavior/data_objects/base/__init__.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/__init__.py rename to allensdk/brain_observatory/behavior/data_objects/base/__init__.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/_data_object_abc.py rename to allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/__init__.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/__init__.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/__init__.py rename to allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/__init__.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/internal_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/internal_readable_interface.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/internal_readable_interface.py rename to allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/internal_readable_interface.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/json_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/json_readable_interface.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/json_readable_interface.py rename to allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/json_readable_interface.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/lims_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/lims_readable_interface.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/lims_readable_interface.py rename to allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/lims_readable_interface.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/nwb_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/nwb_readable_interface.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/nwb_readable_interface.py rename to allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/nwb_readable_interface.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/stimulus_file_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/stimulus_file_readable_interface.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/stimulus_file_readable_interface.py rename to allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/stimulus_file_readable_interface.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/sync_file_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/sync_file_readable_interface.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/readable_interfaces/sync_file_readable_interface.py rename to allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/sync_file_readable_interface.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/__init__.py b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/__init__.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/__init__.py rename to allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/__init__.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/json_writable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/json_writable_interface.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/json_writable_interface.py rename to allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/json_writable_interface.py diff --git a/allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/nwb_writable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py similarity index 100% rename from allensdk/brain_observatory/behavior/data_objects/_base/writable_interfaces/nwb_writable_interface.py rename to allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index fa539231c..1d4c3a72f 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -8,20 +8,20 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject, \ StimulusTimestamps, BehaviorSessionId -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .internal_readable_interface \ import \ InternalReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface -from allensdk.brain_observatory.behavior.data_objects._base.writable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.writable_interfaces\ .nwb_writable_interface import \ NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py index b58048724..17d97c79b 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py @@ -3,16 +3,16 @@ from cachetools import cached, LRUCache from cachetools.keys import hashkey -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py index 32c63af95..d4bd610ea 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py @@ -5,10 +5,10 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .stimulus_file_readable_interface import \ StimulusFileReadableInterface diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py index a91f524c3..2e93e3474 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py @@ -6,16 +6,16 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py index b4690c868..79449c7dd 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py @@ -1,16 +1,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py index b2d38f656..3df29a668 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py @@ -3,13 +3,13 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py index fdace9a50..72af578e2 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py @@ -2,10 +2,10 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .stimulus_file_readable_interface \ import \ StimulusFileReadableInterface diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py index f44bcd2c5..e6a49a0c7 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py @@ -2,10 +2,10 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject, \ StimulusTimestamps -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .stimulus_file_readable_interface \ import \ StimulusFileReadableInterface diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py index 7439b25c0..d7289779f 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py @@ -5,16 +5,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py index a0cde264c..0b286b868 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py @@ -3,16 +3,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin, \ diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py index ce29051cf..a0a371383 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py @@ -4,16 +4,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py index f22a355ec..e03e883e9 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py @@ -1,16 +1,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py index ae9800ed3..84479e807 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py @@ -4,16 +4,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin, \ diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py index d1df49220..29437bbe0 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py @@ -1,16 +1,16 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py index 99b479508..34fc1d785 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py @@ -4,16 +4,16 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject, \ BehaviorSessionId -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface -from allensdk.brain_observatory.behavior.data_objects._base.writable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.writable_interfaces\ .nwb_writable_interface import \ NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py index 59ed6e128..1a211baec 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py @@ -10,16 +10,16 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.nwb_writable_interface import \ NwbWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py index 6afca1e36..123725a91 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py @@ -10,19 +10,19 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.json_readable_interface import \ JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.lims_readable_interface import \ LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.nwb_writable_interface import \ NwbWritableInterface from allensdk.core.exceptions import DataFrameIndexError diff --git a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py index f64391213..b1d3108e1 100644 --- a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py +++ b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py @@ -8,24 +8,24 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .stimulus_file_readable_interface \ import \ StimulusFileReadableInterface -from allensdk.brain_observatory.behavior.data_objects._base.readable_interfaces\ +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .sync_file_readable_interface import \ SyncFileReadableInterface from allensdk.brain_observatory.behavior.data_objects import DataObject from allensdk.brain_observatory.behavior.data_files import ( StimulusFile, SyncFile ) -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.json_writable_interface import \ JsonWritableInterface -from allensdk.brain_observatory.behavior.data_objects._base\ +from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces.nwb_writable_interface import \ NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.stimulus_timestamps.timestamps_processing import ( # noqa: E501 From 4902de81d92c9e5e0f4ba9c73d33822da250df73 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 8 Jun 2021 11:56:40 -0700 Subject: [PATCH 031/234] behavior metadata has subject metadata --- .../behavior_metadata/behavior_metadata.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index 1d4c3a72f..e9ea0d5c5 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -42,8 +42,10 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.stimulus_frame_rate import \ StimulusFrameRate -from allensdk.brain_observatory.behavior.schemas import SubjectMetadataSchema, \ - BehaviorMetadataSchema +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.subject_metadata import \ + SubjectMetadata +from allensdk.brain_observatory.behavior.schemas import BehaviorMetadataSchema from allensdk.brain_observatory.nwb import load_pynwb_extension from allensdk.brain_observatory.session_api_utils import compare_session_fields from allensdk.internal.api import PostgresQueryMixin @@ -194,6 +196,7 @@ class BehaviorMetadata(DataObject, InternalReadableInterface, NwbWritableInterface): """Container class for behavior metadata""" def __init__(self, + subject_metadata: SubjectMetadata, behavior_session_id: BehaviorSessionId, equipment_name: EquipmentName, stimulus_frame_rate: StimulusFrameRate, @@ -201,6 +204,7 @@ def __init__(self, date_of_acquisition: DateOfAcquisition, behavior_session_uuid: BehaviorSessionUUID): super().__init__(name='behavior_metadata', value=self) + self._subject_metadata = subject_metadata self._behavior_session_id = behavior_session_id self._equipment_name = equipment_name self._stimulus_frame_rate = stimulus_frame_rate @@ -218,6 +222,8 @@ def from_internal( stimulus_timestamps: StimulusTimestamps, lims_db: PostgresQueryMixin ) -> "BehaviorMetadata": + subject_metadata = SubjectMetadata.from_lims( + behavior_session_id=behavior_session_id, lims_db=lims_db) equipment_name = EquipmentName.from_lims( behavior_session_id=behavior_session_id.value, lims_db=lims_db) stimulus_frame_rate = StimulusFrameRate.from_stimulus_file( @@ -238,6 +244,7 @@ def from_internal( stimulus_file=stimulus_file) return cls( + subject_metadata=subject_metadata, behavior_session_id=behavior_session_id, equipment_name=equipment_name, stimulus_frame_rate=stimulus_frame_rate, @@ -252,6 +259,8 @@ def from_json(cls, dict_repr: dict) -> "BehaviorMetadata": @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorMetadata": + subject_metadata = SubjectMetadata.from_nwb(nwbfile=nwbfile) + behavior_session_id = BehaviorSessionId.from_nwb(nwbfile=nwbfile) equipment_name = EquipmentName.from_nwb(nwbfile=nwbfile) stimulus_frame_rate = StimulusFrameRate.from_nwb(nwbfile=nwbfile) @@ -260,6 +269,7 @@ def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorMetadata": session_uuid = BehaviorSessionUUID.from_nwb(nwbfile=nwbfile) return cls( + subject_metadata=subject_metadata, behavior_session_id=behavior_session_id, equipment_name=equipment_name, stimulus_frame_rate=stimulus_frame_rate, @@ -301,6 +311,8 @@ def to_json(self) -> dict: pass def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + self._subject_metadata.to_nwb(nwbfile=nwbfile) + extension = load_pynwb_extension(BehaviorMetadataSchema, 'ndx-aibs-behavior-ophys') nwb_metadata = extension( From 7f33322cf490033fcd71547d3955b01a3f8758ec Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 8 Jun 2021 12:12:29 -0700 Subject: [PATCH 032/234] implements from_json for behavior/subject --- .../behavior_metadata/behavior_metadata.py | 27 +++++++++++++++++-- .../behavior_metadata/date_of_acquisition.py | 7 ++++- .../metadata/subject_metadata/driver_line.py | 2 +- .../subject_metadata/full_genotype.py | 2 +- .../metadata/subject_metadata/mouse_id.py | 1 + .../subject_metadata/reporter_line.py | 4 ++- .../subject_metadata/subject_metadata.py | 24 ++++++++++++++++- 7 files changed, 60 insertions(+), 7 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index e9ea0d5c5..0764a0801 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -255,7 +255,30 @@ def from_internal( @classmethod def from_json(cls, dict_repr: dict) -> "BehaviorMetadata": - pass + subject_metadata = SubjectMetadata.from_json(dict_repr=dict_repr) + behavior_session_id = BehaviorSessionId.from_json(dict_repr=dict_repr) + equipment_name = EquipmentName.from_json(dict_repr=dict_repr) + date_of_acquisition = DateOfAcquisition.from_json(dict_repr=dict_repr) + + stimulus_file = StimulusFile.from_json(dict_repr=dict_repr) + stimulus_timestamps = StimulusTimestamps.from_stimulus_file( + stimulus_file=stimulus_file) + stimulus_frame_rate = StimulusFrameRate.from_stimulus_file( + stimulus_timestamps=stimulus_timestamps) + session_type = SessionType.from_stimulus_file( + stimulus_file=stimulus_file) + session_uuid = BehaviorSessionUUID.from_stimulus_file( + stimulus_file=stimulus_file) + + return cls( + subject_metadata=subject_metadata, + behavior_session_id=behavior_session_id, + equipment_name=equipment_name, + stimulus_frame_rate=stimulus_frame_rate, + session_type=session_type, + date_of_acquisition=date_of_acquisition, + behavior_session_uuid=session_uuid, + ) @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorMetadata": @@ -312,7 +335,7 @@ def to_json(self) -> dict: def to_nwb(self, nwbfile: NWBFile) -> NWBFile: self._subject_metadata.to_nwb(nwbfile=nwbfile) - + extension = load_pynwb_extension(BehaviorMetadataSchema, 'ndx-aibs-behavior-ophys') nwb_metadata = extension( diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py index 2e93e3474..d881051dc 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py @@ -28,8 +28,13 @@ class DateOfAcquisition(DataObject, LimsReadableInterface, def __init__(self, date_of_acquisition: float): super().__init__(name="date_of_acquisition", value=date_of_acquisition) + @classmethod def from_json(cls, dict_repr: dict) -> "DateOfAcquisition": - pass + tz = pytz.timezone("America/Los_Angeles") + doa = dict_repr['date_of_acquisition'] + doa = tz.localize(datetime.strptime(doa, "%Y-%m-%d %H:%M:%S")) + doa = doa.astimezone(pytz.utc) + return cls(date_of_acquisition=doa) def to_json(self) -> dict: return {"stimulus_frame_rate": self.value} diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py index 0b286b868..dfc84a04e 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py @@ -27,7 +27,7 @@ def __init__(self, driver_line: List[str]): @classmethod def from_json(cls, dict_repr: dict) -> "DriverLine": - pass + return cls(driver_line=dict_repr['driver_line']) def to_json(self) -> dict: return {"sex": self.value} diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py index a0a371383..4b6fe8b06 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py @@ -27,7 +27,7 @@ def __init__(self, full_genotype: str): @classmethod def from_json(cls, dict_repr: dict) -> "FullGenotype": - pass + return cls(full_genotype=dict_repr['full_genotype']) def to_json(self) -> dict: return {"sex": self.value} diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py index e03e883e9..7b02098f4 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py @@ -25,6 +25,7 @@ def __init__(self, mouse_id: int): @classmethod def from_json(cls, dict_repr: dict) -> "MouseId": mouse_id = dict_repr['external_specimen_name'] + mouse_id = int(mouse_id) return cls(mouse_id=mouse_id) def to_json(self) -> dict: diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py index 84479e807..e807dc7e5 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py @@ -28,7 +28,9 @@ def __init__(self, reporter_line: Optional[str]): @classmethod def from_json(cls, dict_repr: dict) -> "ReporterLine": - pass + reporter_line = dict_repr['reporter_line'] + reporter_line = cls._parse(reporter_line=reporter_line, warn=True) + return cls(reporter_line=reporter_line) def to_json(self) -> dict: return {"sex": self.value} diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py index 34fc1d785..228bba5cc 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py @@ -4,6 +4,9 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject, \ BehaviorSessionId +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ .lims_readable_interface import \ LimsReadableInterface @@ -40,7 +43,8 @@ class SubjectMetadata(DataObject, LimsReadableInterface, NwbReadableInterface, - NwbWritableInterface, JsonWritableInterface): + NwbWritableInterface, JsonReadableInterface, + JsonWritableInterface): """Subject metadata""" def __init__(self, sex: Sex, @@ -83,6 +87,24 @@ def from_lims(cls, reporter_line=reporter_line ) + @classmethod + def from_json(cls, dict_repr: dict) -> "SubjectMetadata": + sex = Sex.from_json(dict_repr=dict_repr) + age = Age.from_json(dict_repr=dict_repr) + reporter_line = ReporterLine.from_json(dict_repr=dict_repr) + full_genotype = FullGenotype.from_json(dict_repr=dict_repr) + driver_line = DriverLine.from_json(dict_repr=dict_repr) + mouse_id = MouseId.from_json(dict_repr=dict_repr) + + return cls( + sex=sex, + age=age, + full_genotype=full_genotype, + driver_line=driver_line, + mouse_id=mouse_id, + reporter_line=reporter_line + ) + def to_json(self) -> dict: pass From 264fd1f2d17b90180fe72dee10c9ad4ef228ac08 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 8 Jun 2021 12:25:38 -0700 Subject: [PATCH 033/234] correct instance method, not classmethdo --- .../writable_interfaces/nwb_writable_interface.py | 1 - .../metadata/subject_metadata/subject_metadata.py | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py index fc00f7eaf..83c4e5cf5 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py @@ -7,7 +7,6 @@ class NwbWritableInterface(abc.ABC): """Marks a data object as writable to NWB""" - @classmethod @abc.abstractmethod def to_nwb(self, nwbfile: NWBFile) -> NWBFile: # pragma: no cover """Given an already populated DataObject, return an pyNWB file object diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py index 228bba5cc..4b781ec5d 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py @@ -126,18 +126,17 @@ def from_nwb(cls, nwbfile: NWBFile) -> "SubjectMetadata": full_genotype=genotype ) - @classmethod - def to_nwb(cls, nwbfile: NWBFile) -> NWBFile: + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: BehaviorSubject = load_pynwb_extension(SubjectMetadataSchema, 'ndx-aibs-behavior-ophys') nwb_subject = BehaviorSubject( description="A visual behavior subject with a LabTracks ID", - age=Age.to_iso8601(age=cls.age_in_days), - driver_line=cls.driver_line, - genotype=cls.full_genotype, - subject_id=str(cls.mouse_id), - reporter_line=cls.reporter_line, - sex=cls.sex, + age=Age.to_iso8601(age=self.age_in_days), + driver_line=self.driver_line, + genotype=self.full_genotype, + subject_id=str(self.mouse_id), + reporter_line=self.reporter_line, + sex=self.sex, species='Mus musculus') nwbfile.subject = nwb_subject return nwbfile From 8a9d4727d7bc3d4e9d50a44707fdfff5e0724a00 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 8 Jun 2021 12:56:28 -0700 Subject: [PATCH 034/234] adds metadata to behavior session class --- .../behavior/behavior_session.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index 1aab97c1a..07340c64c 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -95,13 +95,16 @@ def from_json(cls, session_data: dict) -> "BehaviorSession": session_data, filtered=False ) running_speed = RunningSpeed.from_json(session_data) + metadata = BehaviorMetadata.from_json(session_data) + return cls( api=BehaviorJsonApi(session_data), behavior_session_id=behavior_session_id, stimulus_timestamps=stimulus_timestamps, running_acquisition=running_acquisition, raw_running_speed=raw_running_speed, - running_speed=running_speed + running_speed=running_speed, + metadata=metadata ) @classmethod @@ -147,13 +150,15 @@ def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorSession": running_acquisition = RunningAcquisition.from_nwb(nwbfile) raw_running_speed = RunningSpeed.from_nwb(nwbfile, filtered=False) running_speed = RunningSpeed.from_nwb(nwbfile) + metadata = BehaviorMetadata.from_nwb(nwbfile) return cls( behavior_session_id=behavior_session_id, stimulus_timestamps=stimulus_timestamps, running_acquisition=running_acquisition, raw_running_speed=raw_running_speed, - running_speed=running_speed + running_speed=running_speed, + metadata=metadata ) @classmethod @@ -166,7 +171,12 @@ def to_json(self) -> dict: pass def to_nwb(self, nwbfile: NWBFile) -> NWBFile: - pass + self._stimulus_timestamps.to_nwb(nwbfile=nwbfile) + self._running_acquisition.to_nwb(nwbfile=nwbfile) + self._running_speed.to_nwb(nwbfile=nwbfile) + self._metadata.to_nwb(nwbfile=nwbfile) + + return nwbfile def cache_clear(self) -> None: """Convenience method to clear the api cache, if applicable.""" From 7b152ff2278e50a0a2f2199b9dcbbc6e4d7a6198 Mon Sep 17 00:00:00 2001 From: aamster Date: Fri, 11 Jun 2021 07:11:46 -0700 Subject: [PATCH 035/234] working ophys, mesoscope metadata from_internal --- .../behavior_ophys_metadata.py | 91 ---------- .../emission_lambda.py | 21 +++ .../excitation_lambda.py | 20 +++ .../experiment_container_id.py | 41 +++++ .../field_of_view_shape.py | 54 ++++++ .../imaging_depth.py | 41 +++++ .../mesoscope_experiment_metadata/__init__.py | 0 .../imaging_plane_group.py | 64 +++++++ .../mesoscope_experiment_metadata.py | 127 +++++++++++++ .../ophys_experiment_metadata.py | 170 ++++++++++++++++++ .../ophys_frame_rate.py | 34 ++++ .../ophys_experiment_metadata/project_code.py | 26 +++ .../targeted_structure.py | 46 +++++ .../abcs/session_base/behavior_ophys_base.py | 6 +- .../data_io/behavior_ophys_nwb_api.py | 6 +- .../behavior_ophys_data_transforms.py | 10 +- 16 files changed, 655 insertions(+), 102 deletions(-) delete mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/behavior_ophys_metadata.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/emission_lambda.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/excitation_lambda.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/experiment_container_id.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/field_of_view_shape.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_depth.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/__init__.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/imaging_plane_group.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_frame_rate.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/project_code.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/targeted_structure.py diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/behavior_ophys_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/behavior_ophys_metadata.py deleted file mode 100644 index 63779a3b3..000000000 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/behavior_ophys_metadata.py +++ /dev/null @@ -1,91 +0,0 @@ -import numpy as np -from typing import Optional - -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.behavior_metadata import \ - BehaviorMetadata -from allensdk.brain_observatory.behavior.session_apis.abcs.\ - data_extractor_base.behavior_ophys_data_extractor_base import \ - BehaviorOphysDataExtractorBase - - -class BehaviorOphysMetadata(BehaviorMetadata): - """Container class for behavior ophys metadata""" - def __init__(self, extractor: BehaviorOphysDataExtractorBase, - stimulus_timestamps: np.ndarray, - ophys_timestamps: np.ndarray, - behavior_stimulus_file: dict): - - super().__init__(extractor=extractor, - stimulus_timestamps=stimulus_timestamps, - behavior_stimulus_file=behavior_stimulus_file) - self._extractor = extractor - self._ophys_timestamps = ophys_timestamps - - # project_code needs to be excluded from comparison - # since it's only exposed internally - self._exclude_from_equals = {'project_code'} - - @property - def emission_lambda(self) -> float: - return 520.0 - - @property - def excitation_lambda(self) -> float: - return 910.0 - - # TODO rename to ophys_container_id - @property - def experiment_container_id(self) -> int: - return self._extractor.get_ophys_container_id() - - @property - def field_of_view_height(self) -> int: - return self._extractor.get_field_of_view_shape()['height'] - - @property - def field_of_view_width(self) -> int: - return self._extractor.get_field_of_view_shape()['width'] - - @property - def imaging_depth(self) -> int: - return self._extractor.get_imaging_depth() - - @property - def imaging_plane_group(self) -> Optional[int]: - return self._extractor.get_imaging_plane_group() - - @property - def imaging_plane_group_count(self) -> int: - return self._extractor.get_plane_group_count() - - @property - def ophys_experiment_id(self) -> int: - return self._extractor.get_ophys_experiment_id() - - @property - def ophys_frame_rate(self) -> float: - return self._get_frame_rate(timestamps=self._ophys_timestamps) - - @property - def ophys_session_id(self) -> int: - return self._extractor.get_ophys_session_id() - - @property - def project_code(self) -> Optional[str]: - try: - project_code = self._extractor.get_project_code() - except NotImplementedError: - # Project code only returned by LIMS - project_code = None - return project_code - - @property - def targeted_structure(self) -> str: - return self._extractor.get_targeted_structure() - - def to_dict(self) -> dict: - """Returns dict representation of all properties in class""" - vars_ = vars(BehaviorOphysMetadata) - d = self._get_properties(vars_=vars_) - return {**super().to_dict(), **d} diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/emission_lambda.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/emission_lambda.py new file mode 100644 index 000000000..a03bc8fbb --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/emission_lambda.py @@ -0,0 +1,21 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface + + +class EmissionLambda(DataObject, NwbReadableInterface): + def __init__(self, emission_lambda=520.0): + super().__init__(name='emission_lambda', value=emission_lambda) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "EmissionLambda": + ophys_module = nwbfile.processing['ophys'] + image_seg = ophys_module.data_interfaces['image_segmentation'] + imaging_plane = image_seg.plane_segmentations[ + 'cell_specimen_table'].imaging_plane + optical_channel = imaging_plane.optical_channel[0] + emission_lambda = optical_channel.emission_lambda + return cls(emission_lambda=emission_lambda) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/excitation_lambda.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/excitation_lambda.py new file mode 100644 index 000000000..910437074 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/excitation_lambda.py @@ -0,0 +1,20 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface + + +class ExcitationLambda(DataObject, NwbReadableInterface): + def __init__(self, excitation_lambda=910.0): + super().__init__(name='excitation_lambda', value=excitation_lambda) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "ExcitationLambda": + ophys_module = nwbfile.processing['ophys'] + image_seg = ophys_module.data_interfaces['image_segmentation'] + imaging_plane = image_seg.plane_segmentations[ + 'cell_specimen_table'].imaging_plane + excitation_lambda = imaging_plane.excitation_lambda + return cls(excitation_lambda=excitation_lambda) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/experiment_container_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/experiment_container_id.py new file mode 100644 index 000000000..d6d0ec29f --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/experiment_container_id.py @@ -0,0 +1,41 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface +from allensdk.internal.api import PostgresQueryMixin + + +class ExperimentContainerId(DataObject, LimsReadableInterface, + JsonReadableInterface, NwbReadableInterface): + """"experiment container id""" + def __init__(self, experiment_container_id: int): + super().__init__(name='experiment_container_id', + value=experiment_container_id) + + @classmethod + def from_lims(cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> "ExperimentContainerId": + query = """ + SELECT visual_behavior_experiment_container_id + FROM ophys_experiments_visual_behavior_experiment_containers + WHERE ophys_experiment_id = {}; + """.format(ophys_experiment_id) + container_id = lims_db.fetchone(query, strict=False) + return cls(experiment_container_id=container_id) + + @classmethod + def from_json(cls, dict_repr: dict) -> "ExperimentContainerId": + return cls(experiment_container_id=dict_repr['container_id']) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "ExperimentContainerId": + metadata = nwbfile.lab_meta_data['metadata'] + return cls(experiment_container_id=metadata.experiment_container_id) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/field_of_view_shape.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/field_of_view_shape.py new file mode 100644 index 000000000..c02074102 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/field_of_view_shape.py @@ -0,0 +1,54 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface +from allensdk.internal.api import PostgresQueryMixin + + +class FieldOfViewShape(DataObject, LimsReadableInterface, + NwbReadableInterface, JsonReadableInterface): + def __init__(self, height: int, width: int): + super().__init__(name='field_of_view_shape', value=self) + + self._height = height + self._width = width + + @property + def height(self): + return self._height + + @property + def width(self): + return self._width + + @classmethod + def from_lims(cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> "FieldOfViewShape": + query = f""" + SELECT oe.movie_width as width, oe.movie_height as height + FROM ophys_experiments oe + WHERE oe.id = {ophys_experiment_id}; + """ + df = lims_db.select(query=query) + height = df.iloc[0]['height'] + width = df.iloc[0]['width'] + return cls(height=height, width=width) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "FieldOfViewShape": + metadata = nwbfile.lab_meta_data['metadata'] + return cls(height=metadata.field_of_view_height, + width=metadata.field_of_view_width) + + @classmethod + def from_json(cls, dict_repr: dict) -> "FieldOfViewShape": + return cls(height=dict_repr['movie_height'], + width=dict_repr['movie_width']) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_depth.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_depth.py new file mode 100644 index 000000000..c0efd9707 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_depth.py @@ -0,0 +1,41 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface +from allensdk.internal.api import PostgresQueryMixin + + +class ImagingDepth(DataObject, LimsReadableInterface, NwbReadableInterface, + JsonReadableInterface): + def __init__(self, imaging_depth: int): + super().__init__(name='imaging_depth', value=imaging_depth) + + @classmethod + def from_lims(cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> "ImagingDepth": + query = """ + SELECT id.depth + FROM ophys_experiments oe + JOIN ophys_sessions os ON oe.ophys_session_id = os.id + LEFT JOIN imaging_depths id ON id.id = oe.imaging_depth_id + WHERE oe.id = {}; + """.format(ophys_experiment_id) + imaging_depth = lims_db.fetchone(query, strict=True) + return cls(imaging_depth=imaging_depth) + + @classmethod + def from_json(cls, dict_repr: dict) -> "ImagingDepth": + return cls(imaging_depth=dict_repr['targeted_depth']) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "ImagingDepth": + metadata = nwbfile.lab_meta_data['metadata'] + return cls(imaging_depth=metadata.imaging_depth) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/__init__.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/imaging_plane_group.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/imaging_plane_group.py new file mode 100644 index 000000000..51ff376ff --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/imaging_plane_group.py @@ -0,0 +1,64 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface +from allensdk.internal.api import PostgresQueryMixin + + +class ImagingPlaneGroup(DataObject, LimsReadableInterface, + JsonReadableInterface, NwbReadableInterface): + def __init__(self, plane_group: int, plane_group_count: int): + super().__init__(name='plane_group', value=self) + self._plane_group = plane_group + self._plane_group_count = plane_group_count + + @property + def plane_group(self): + return self._plane_group + + @property + def plane_group_count(self): + return self._plane_group_count + + @classmethod + def from_lims(cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> "ImagingPlaneGroup": + query = f''' + SELECT oe.id as ophys_experiment_id, pg.group_order AS plane_group + FROM ophys_experiments oe + JOIN ophys_sessions os ON oe.ophys_session_id = os.id + JOIN ophys_imaging_plane_groups pg + ON pg.id = oe.ophys_imaging_plane_group_id + WHERE os.id = ( + SELECT oe.ophys_session_id + FROM ophys_experiments oe + WHERE oe.id = {ophys_experiment_id} + ) + ''' + df = lims_db.select(query=query) + df = df.set_index('ophys_experiment_id') + plane_group = df.loc[ophys_experiment_id, 'plane_group'] + plane_group_count = df['plane_group'].nunique() + return cls(plane_group=plane_group, + plane_group_count=plane_group_count) + + @classmethod + def from_json(cls, dict_repr: dict) -> "ImagingPlaneGroup": + plane_group = dict_repr['imaging_plane_group'] + plane_group_count = dict_repr['plane_group_count'] + return cls(plane_group=plane_group, + plane_group_count=plane_group_count) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "ImagingPlaneGroup": + metadata = nwbfile.lab_meta_data['metadata'] + return cls(plane_group=metadata.imaging_plane_group, + plane_group_count=metadata.imaging_plane_group_count) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py new file mode 100644 index 000000000..b736b8143 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py @@ -0,0 +1,127 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.internal_readable_interface import \ + InternalReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.ophys_experiment_metadata import \ + OphysExperimentMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.emission_lambda import \ + EmissionLambda +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.excitation_lambda import \ + ExcitationLambda +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.experiment_container_id import \ + ExperimentContainerId +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.field_of_view_shape import \ + FieldOfViewShape +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.imaging_depth import \ + ImagingDepth +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.mesoscope_experiment_metadata\ + .imaging_plane_group import \ + ImagingPlaneGroup +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.ophys_frame_rate import \ + OphysFrameRate +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.project_code import \ + ProjectCode +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.targeted_structure import \ + TargetedStructure +from allensdk.internal.api import PostgresQueryMixin + + +class MesoscopeExperimentMetadata(OphysExperimentMetadata): + def __init__(self, + experiment_container_id: ExperimentContainerId, + emission_lambda: EmissionLambda, + excitation_lambda: ExcitationLambda, + field_of_view_shape: FieldOfViewShape, + imaging_depth: ImagingDepth, + imaging_plane_group: ImagingPlaneGroup, + ophys_frame_rate: OphysFrameRate, + project_code: ProjectCode, + targeted_structure: TargetedStructure): + super().__init__( + experiment_container_id=experiment_container_id, + emission_lambda=emission_lambda, + excitation_lambda=excitation_lambda, + field_of_view_shape=field_of_view_shape, + imaging_depth=imaging_depth, + ophys_frame_rate=ophys_frame_rate, + project_code=project_code, + targeted_structure=targeted_structure + ) + self._imaging_plane_group = imaging_plane_group + + @classmethod + def from_internal( + cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> "MesoscopeExperimentMetadata": + ophys_experiment_metadata = OphysExperimentMetadata.from_internal( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + imaging_plane_group = ImagingPlaneGroup.from_lims( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + return cls( + experiment_container_id= + ophys_experiment_metadata._experiment_container_id, + emission_lambda=ophys_experiment_metadata._emission_lambda, + excitation_lambda=ophys_experiment_metadata._excitation_lambda, + field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, + imaging_depth=ophys_experiment_metadata._imaging_depth, + ophys_frame_rate=ophys_experiment_metadata._ophys_frame_rate, + project_code=ophys_experiment_metadata._project_code, + targeted_structure=ophys_experiment_metadata._targeted_structure, + imaging_plane_group=imaging_plane_group + ) + + @classmethod + def from_json(cls, dict_repr: dict) -> "MesoscopeExperimentMetadata": + ophys_experiment_metadata = super().from_json(dict_repr=dict_repr) + imaging_plane_group = ImagingPlaneGroup.from_json(dict_repr=dict_repr) + return cls( + experiment_container_id= + ophys_experiment_metadata._experiment_container_id, + emission_lambda=ophys_experiment_metadata._emission_lambda, + excitation_lambda=ophys_experiment_metadata._excitation_lambda, + field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, + imaging_depth=ophys_experiment_metadata._imaging_depth, + imaging_plane_group=imaging_plane_group + ) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "MesoscopeExperimentMetadata": + ophys_experiment_metadata = super().from_nwb(nwbfile=nwbfile) + imaging_plane_group = ImagingPlaneGroup.from_nwb(nwbfile=nwbfile) + return cls( + experiment_container_id= + ophys_experiment_metadata._experiment_container_id, + emission_lambda=ophys_experiment_metadata._emission_lambda, + excitation_lambda=ophys_experiment_metadata._excitation_lambda, + field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, + imaging_depth=ophys_experiment_metadata._imaging_depth, + imaging_plane_group=imaging_plane_group + ) + + @property + def imaging_plane_group(self) -> int: + return self._imaging_plane_group.plane_group + + @property + def imaging_plane_group_count(self) -> int: + # TODO this is at the wrong level of abstraction. + # It is an attribute of the session, not the experiment. + # Currently, an Ophys Session metadata abstraction doesn't exist + return self._imaging_plane_group.plane_group_count diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py new file mode 100644 index 000000000..c75211b90 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py @@ -0,0 +1,170 @@ +from typing import Optional + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_files import SyncFile +from allensdk.brain_observatory.behavior.data_objects import DataObject, \ + StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.internal_readable_interface import \ + InternalReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.stimulus_frame_rate import \ + StimulusFrameRate +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.emission_lambda import \ + EmissionLambda +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.excitation_lambda import \ + ExcitationLambda +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.experiment_container_id import \ + ExperimentContainerId +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.field_of_view_shape import \ + FieldOfViewShape +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.imaging_depth import \ + ImagingDepth +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.ophys_frame_rate import \ + OphysFrameRate +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.project_code import \ + ProjectCode +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.targeted_structure import \ + TargetedStructure +from allensdk.internal.api import PostgresQueryMixin + + +class OphysExperimentMetadata(DataObject, InternalReadableInterface, + JsonReadableInterface, NwbReadableInterface): + """Container class for behavior ophys metadata""" + # def __init__(self, extractor: BehaviorOphysDataExtractorBase, + # stimulus_timestamps: np.ndarray, + # ophys_timestamps: np.ndarray, + # behavior_stimulus_file: dict): + def __init__(self, + experiment_container_id: ExperimentContainerId, + emission_lambda: EmissionLambda, + excitation_lambda: ExcitationLambda, + field_of_view_shape: FieldOfViewShape, + imaging_depth: ImagingDepth, + ophys_frame_rate: OphysFrameRate, + project_code: ProjectCode, + targeted_structure: TargetedStructure): + super().__init__(name='ophys_experiment_metadata', value=self) + self._experiment_container_id = experiment_container_id + self._emission_lambda = emission_lambda + self._excitation_lambda = excitation_lambda + self._field_of_view_shape = field_of_view_shape + self._imaging_depth = imaging_depth + self._ophys_frame_rate = ophys_frame_rate + self._project_code = project_code + self._targeted_structure = targeted_structure + + # project_code needs to be excluded from comparison + # since it's only exposed internally + self._exclude_from_equals = {'project_code'} + + @classmethod + def from_internal( + cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> "OphysExperimentMetadata": + experiment_container_id = ExperimentContainerId.from_lims( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + emission_lambda = EmissionLambda(emission_lambda=520.0) + excitation_lambda = ExcitationLambda(excitation_lambda=910.0) + field_of_view_shape = FieldOfViewShape.from_lims( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + imaging_depth = ImagingDepth.from_lims( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + + sync_file = SyncFile.from_lims(ophys_experiment_id=ophys_experiment_id, + db=lims_db) + timestamps = StimulusTimestamps.from_sync_file(sync_file=sync_file) + ophys_frame_rate = OphysFrameRate.from_stimulus_file( + stimulus_timestamps=timestamps) + project_code = ProjectCode.from_lims( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + targeted_structure = TargetedStructure.from_lims( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + return cls( + emission_lambda=emission_lambda, + excitation_lambda=excitation_lambda, + experiment_container_id=experiment_container_id, + field_of_view_shape=field_of_view_shape, + imaging_depth=imaging_depth, + ophys_frame_rate=ophys_frame_rate, + project_code=project_code, + targeted_structure=targeted_structure + ) + + @classmethod + def from_json(cls, dict_repr: dict) -> "OphysExperimentMetadata": + pass + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "OphysExperimentMetadata": + pass + + @property + def emission_lambda(self) -> float: + return self._emission_lambda.value + + @property + def excitation_lambda(self) -> float: + return self._excitation_lambda.value + + # TODO rename to ophys_container_id + @property + def experiment_container_id(self) -> int: + return self._experiment_container_id.value + + @property + def field_of_view_height(self) -> int: + return self._field_of_view_shape.height + + @property + def field_of_view_width(self) -> int: + return self._field_of_view_shape.width + + @property + def imaging_depth(self) -> int: + return self._imaging_depth.value + + @property + def ophys_experiment_id(self) -> int: + # TODO remove this. Should be at Ophys experiment class level + return 0 + + @property + def ophys_frame_rate(self) -> float: + return self._ophys_frame_rate.value + + @property + def ophys_session_id(self) -> int: + # TODO this is at the wrong layer of abstraction. + # Should be at ophys session level + return 0 + + @property + def project_code(self) -> Optional[str]: + return self._project_code.value + + @property + def targeted_structure(self) -> str: + return self._targeted_structure.value + + def to_dict(self) -> dict: + """Returns dict representation of all properties in class""" + vars_ = vars(OphysExperimentMetadata) + d = self._get_properties(vars_=vars_) + return {**super().to_dict(), **d} diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_frame_rate.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_frame_rate.py new file mode 100644 index 000000000..fd00abe4b --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_frame_rate.py @@ -0,0 +1,34 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject, \ + StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ + .stimulus_file_readable_interface \ + import \ + StimulusFileReadableInterface + + +class OphysFrameRate(DataObject, StimulusFileReadableInterface, + NwbReadableInterface): + """Ophys frame rate""" + def __init__(self, ophys_frame_rate: float): + super().__init__(name="ophys_frame_rate", value=ophys_frame_rate) + + @classmethod + def from_stimulus_file( + cls, + stimulus_timestamps: StimulusTimestamps) -> "OphysFrameRate": + frame_rate = stimulus_timestamps.calc_frame_rate() + return cls(ophys_frame_rate=frame_rate) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "OphysFrameRate": + ophys_module = nwbfile.processing['ophys'] + image_seg = ophys_module.data_interfaces['image_segmentation'] + imaging_plane = image_seg.plane_segmentations[ + 'cell_specimen_table'].imaging_plane + ophys_frame_rate = imaging_plane.imaging_rate + return cls(ophys_frame_rate=ophys_frame_rate) \ No newline at end of file diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/project_code.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/project_code.py new file mode 100644 index 000000000..7c76c6d61 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/project_code.py @@ -0,0 +1,26 @@ +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface +from allensdk.internal.api import PostgresQueryMixin + + +class ProjectCode(DataObject, LimsReadableInterface): + def __init__(self, project_code: str): + super().__init__(name='project_code', value=project_code) + + @classmethod + def from_lims(cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> "ProjectCode": + query = f""" + SELECT projects.code AS project_code + FROM ophys_sessions + JOIN projects ON projects.id = ophys_sessions.project_id + WHERE ophys_sessions.id = ( + SELECT oe.ophys_session_id + FROM ophys_experiments oe + WHERE oe.id = {ophys_experiment_id} + ) + """ + project_code = lims_db.fetchone(query, strict=True) + return cls(project_code=project_code) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/targeted_structure.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/targeted_structure.py new file mode 100644 index 000000000..14c8425a9 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/targeted_structure.py @@ -0,0 +1,46 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface +from allensdk.internal.api import PostgresQueryMixin + + +class TargetedStructure(DataObject, LimsReadableInterface, + JsonReadableInterface, NwbReadableInterface): + """targeted structure (acronym) for an ophys experiment + (ex: "Visp")""" + def __init__(self, targeted_structure: str): + super().__init__(name='targeted_structure', value=targeted_structure) + + @classmethod + def from_lims(cls, ophys_experiment_id, + lims_db: PostgresQueryMixin) -> "TargetedStructure": + query = """ + SELECT st.acronym + FROM ophys_experiments oe + LEFT JOIN structures st ON st.id = oe.targeted_structure_id + WHERE oe.id = {}; + """.format(ophys_experiment_id) + targeted_structure = lims_db.fetchone(query, strict=True) + return cls(targeted_structure=targeted_structure) + + @classmethod + def from_json(cls, dict_repr: dict) -> "TargetedStructure": + return cls(targeted_structure=dict_repr['targeted_structure']) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "TargetedStructure": + ophys_module = nwbfile.processing['ophys'] + image_seg = ophys_module.data_interfaces['image_segmentation'] + imaging_plane = image_seg.plane_segmentations[ + 'cell_specimen_table'].imaging_plane + targeted_structure = imaging_plane.location + return cls(targeted_structure=targeted_structure) diff --git a/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_ophys_base.py b/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_ophys_base.py index 108ee5ba4..8b50d61b7 100644 --- a/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_ophys_base.py +++ b/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_ophys_base.py @@ -5,8 +5,8 @@ import pandas as pd from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.behavior_ophys_metadata \ - import BehaviorOphysMetadata + .ophys_experiment_metadata.ophys_experiment_metadata \ + import OphysExperimentMetadata from allensdk.brain_observatory.behavior.session_apis.abcs.\ session_base.behavior_base import BehaviorBase from allensdk.brain_observatory.behavior.image_api import Image @@ -95,7 +95,7 @@ def get_dff_traces(self) -> pd.DataFrame: raise NotImplementedError() @abc.abstractmethod - def get_metadata(self) -> Union[BehaviorOphysMetadata, dict]: + def get_metadata(self) -> Union[OphysExperimentMetadata, dict]: """Get behavior+ophys session metadata. Returns diff --git a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py index 4d5f31e47..e2de4e597 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py @@ -12,8 +12,8 @@ from pynwb import NWBHDF5IO, NWBFile from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.behavior_ophys_metadata \ - import BehaviorOphysMetadata + .ophys_experiment_metadata.ophys_experiment_metadata \ + import OphysExperimentMetadata from allensdk.brain_observatory.behavior.event_detection import \ filter_events_array import allensdk.brain_observatory.nwb as nwb @@ -59,7 +59,7 @@ def save(self, session_object): # Cannot type session_object due to a circular dependency # TODO fix circular dependency and add type - session_metadata: BehaviorOphysMetadata = \ + session_metadata: OphysExperimentMetadata = \ session_object.api.get_metadata() session_type = session_metadata.session_type diff --git a/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py b/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py index d038d42ee..768fda34f 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py @@ -12,8 +12,8 @@ from allensdk.api.warehouse_cache.cache import memoize from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.behavior_ophys_metadata \ - import BehaviorOphysMetadata + .ophys_experiment_metadata.ophys_experiment_metadata \ + import OphysExperimentMetadata from allensdk.brain_observatory.behavior.event_detection import \ filter_events_array from allensdk.brain_observatory.behavior.session_apis.abcs.\ @@ -242,11 +242,11 @@ def _process_ophys_plane_timestamps( return resampled @memoize - def get_metadata(self) -> BehaviorOphysMetadata: + def get_metadata(self) -> OphysExperimentMetadata: """Return metadata about the session. - :rtype: BehaviorOphysMetadata + :rtype: OphysExperimentMetadata """ - metadata = BehaviorOphysMetadata( + metadata = OphysExperimentMetadata( extractor=self.extractor, stimulus_timestamps=self.get_stimulus_timestamps(), ophys_timestamps=self.get_ophys_timestamps(), From 0046cca21d9ee1132000cced9ee3ce052a8686dd Mon Sep 17 00:00:00 2001 From: aamster Date: Fri, 11 Jun 2021 14:09:21 -0700 Subject: [PATCH 036/234] combines multiple data object into imaging_plane --- .../excitation_lambda.py | 20 ---- .../imaging_plane.py | 95 +++++++++++++++++++ .../mesoscope_experiment_metadata.py | 34 +++---- .../ophys_experiment_metadata.py | 59 +++--------- .../ophys_frame_rate.py | 34 ------- .../targeted_structure.py | 46 --------- 6 files changed, 120 insertions(+), 168 deletions(-) delete mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/excitation_lambda.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_plane.py delete mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_frame_rate.py delete mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/targeted_structure.py diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/excitation_lambda.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/excitation_lambda.py deleted file mode 100644 index 910437074..000000000 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/excitation_lambda.py +++ /dev/null @@ -1,20 +0,0 @@ -from pynwb import NWBFile - -from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects.base \ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface - - -class ExcitationLambda(DataObject, NwbReadableInterface): - def __init__(self, excitation_lambda=910.0): - super().__init__(name='excitation_lambda', value=excitation_lambda) - - @classmethod - def from_nwb(cls, nwbfile: NWBFile) -> "ExcitationLambda": - ophys_module = nwbfile.processing['ophys'] - image_seg = ophys_module.data_interfaces['image_segmentation'] - imaging_plane = image_seg.plane_segmentations[ - 'cell_specimen_table'].imaging_plane - excitation_lambda = imaging_plane.excitation_lambda - return cls(excitation_lambda=excitation_lambda) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_plane.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_plane.py new file mode 100644 index 000000000..7c9414d62 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_plane.py @@ -0,0 +1,95 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_files import SyncFile +from allensdk.brain_observatory.behavior.data_objects import DataObject, \ + StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.internal_readable_interface import \ + InternalReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface +from allensdk.internal.api import PostgresQueryMixin + + +class ImagingPlane(DataObject, InternalReadableInterface, + JsonReadableInterface, NwbReadableInterface): + def __init__(self, ophys_frame_rate: float, + targeted_structure: str, + excitation_lambda: float): + super().__init__(name='imaging_plane', value=self) + self._ophys_frame_rate = ophys_frame_rate + self._targeted_structure = targeted_structure + self._excitation_lambda = excitation_lambda + + @classmethod + def from_internal(cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin, + excitation_lambda=910.0) -> "ImagingPlane": + sync_file = SyncFile.from_lims(ophys_experiment_id=ophys_experiment_id, + db=lims_db) + ophys_frame_rate = cls._get_frame_rate_from_sync_file( + sync_file=sync_file) + targeted_structure = cls._get_targeted_structure_from_lims( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + return cls(ophys_frame_rate=ophys_frame_rate, + targeted_structure=targeted_structure, + excitation_lambda=excitation_lambda) + + @classmethod + def from_json(cls, dict_repr: dict, + excitation_lambda=910.0) -> "ImagingPlane": + targeted_structure = dict_repr['targeted_structure'] + sync_file = SyncFile.from_json(dict_repr=dict_repr) + ophys_fame_rate = cls._get_frame_rate_from_sync_file( + sync_file=sync_file) + return cls(targeted_structure=targeted_structure, + ophys_frame_rate=ophys_fame_rate, + excitation_lambda=excitation_lambda) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "ImagingPlane": + ophys_module = nwbfile.processing['ophys'] + image_seg = ophys_module.data_interfaces['image_segmentation'] + imaging_plane = image_seg.plane_segmentations[ + 'cell_specimen_table'].imaging_plane + ophys_frame_rate = imaging_plane.imaging_rate + targeted_structure = imaging_plane.location + excitation_lambda = imaging_plane.excitation_lambda + return cls(ophys_frame_rate=ophys_frame_rate, + targeted_structure=targeted_structure, + excitation_lambda=excitation_lambda) + + @property + def ophys_frame_rate(self) -> float: + return self._ophys_frame_rate + + @property + def targeted_structure(self) -> str: + return self._targeted_structure + + @property + def excitation_lambda(self) -> float: + return self._excitation_lambda + + @staticmethod + def _get_frame_rate_from_sync_file( + sync_file: SyncFile) -> float: + timestamps = StimulusTimestamps.from_sync_file(sync_file=sync_file) + ophys_frame_rate = timestamps.calc_frame_rate() + return ophys_frame_rate + + @staticmethod + def _get_targeted_structure_from_lims(ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> str: + query = """ + SELECT st.acronym + FROM ophys_experiments oe + LEFT JOIN structures st ON st.id = oe.targeted_structure_id + WHERE oe.id = {}; + """.format(ophys_experiment_id) + targeted_structure = lims_db.fetchone(query, strict=True) + return targeted_structure diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py index b736b8143..3b61d3ee4 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py @@ -9,15 +9,15 @@ from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.imaging_plane import \ + ImagingPlane from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.ophys_experiment_metadata import \ OphysExperimentMetadata from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.emission_lambda import \ EmissionLambda -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.excitation_lambda import \ - ExcitationLambda from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.experiment_container_id import \ ExperimentContainerId @@ -31,15 +31,9 @@ .ophys_experiment_metadata.mesoscope_experiment_metadata\ .imaging_plane_group import \ ImagingPlaneGroup -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.ophys_frame_rate import \ - OphysFrameRate from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.project_code import \ ProjectCode -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.targeted_structure import \ - TargetedStructure from allensdk.internal.api import PostgresQueryMixin @@ -47,22 +41,18 @@ class MesoscopeExperimentMetadata(OphysExperimentMetadata): def __init__(self, experiment_container_id: ExperimentContainerId, emission_lambda: EmissionLambda, - excitation_lambda: ExcitationLambda, + imaging_plane: ImagingPlane, field_of_view_shape: FieldOfViewShape, imaging_depth: ImagingDepth, imaging_plane_group: ImagingPlaneGroup, - ophys_frame_rate: OphysFrameRate, - project_code: ProjectCode, - targeted_structure: TargetedStructure): + project_code: ProjectCode): super().__init__( experiment_container_id=experiment_container_id, emission_lambda=emission_lambda, - excitation_lambda=excitation_lambda, + imaging_plane=imaging_plane, field_of_view_shape=field_of_view_shape, imaging_depth=imaging_depth, - ophys_frame_rate=ophys_frame_rate, - project_code=project_code, - targeted_structure=targeted_structure + project_code=project_code ) self._imaging_plane_group = imaging_plane_group @@ -78,12 +68,10 @@ def from_internal( experiment_container_id= ophys_experiment_metadata._experiment_container_id, emission_lambda=ophys_experiment_metadata._emission_lambda, - excitation_lambda=ophys_experiment_metadata._excitation_lambda, + imaging_plane=ophys_experiment_metadata._imaging_plane, field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, imaging_depth=ophys_experiment_metadata._imaging_depth, - ophys_frame_rate=ophys_experiment_metadata._ophys_frame_rate, project_code=ophys_experiment_metadata._project_code, - targeted_structure=ophys_experiment_metadata._targeted_structure, imaging_plane_group=imaging_plane_group ) @@ -95,9 +83,10 @@ def from_json(cls, dict_repr: dict) -> "MesoscopeExperimentMetadata": experiment_container_id= ophys_experiment_metadata._experiment_container_id, emission_lambda=ophys_experiment_metadata._emission_lambda, - excitation_lambda=ophys_experiment_metadata._excitation_lambda, + imaging_plane=ophys_experiment_metadata._imaging_plane, field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, imaging_depth=ophys_experiment_metadata._imaging_depth, + project_code=ophys_experiment_metadata._project_code, imaging_plane_group=imaging_plane_group ) @@ -109,9 +98,10 @@ def from_nwb(cls, nwbfile: NWBFile) -> "MesoscopeExperimentMetadata": experiment_container_id= ophys_experiment_metadata._experiment_container_id, emission_lambda=ophys_experiment_metadata._emission_lambda, - excitation_lambda=ophys_experiment_metadata._excitation_lambda, + imaging_plane=ophys_experiment_metadata._imaging_plane, field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, imaging_depth=ophys_experiment_metadata._imaging_depth, + project_code=ophys_experiment_metadata._project_code, imaging_plane_group=imaging_plane_group ) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py index c75211b90..d1d76a3b0 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py @@ -14,15 +14,9 @@ from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.stimulus_frame_rate import \ - StimulusFrameRate from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.emission_lambda import \ EmissionLambda -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.excitation_lambda import \ - ExcitationLambda from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.experiment_container_id import \ ExperimentContainerId @@ -33,14 +27,11 @@ .ophys_experiment_metadata.imaging_depth import \ ImagingDepth from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.ophys_frame_rate import \ - OphysFrameRate + .ophys_experiment_metadata.imaging_plane import \ + ImagingPlane from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.project_code import \ ProjectCode -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.targeted_structure import \ - TargetedStructure from allensdk.internal.api import PostgresQueryMixin @@ -53,22 +44,18 @@ class OphysExperimentMetadata(DataObject, InternalReadableInterface, # behavior_stimulus_file: dict): def __init__(self, experiment_container_id: ExperimentContainerId, + imaging_plane: ImagingPlane, emission_lambda: EmissionLambda, - excitation_lambda: ExcitationLambda, field_of_view_shape: FieldOfViewShape, imaging_depth: ImagingDepth, - ophys_frame_rate: OphysFrameRate, - project_code: ProjectCode, - targeted_structure: TargetedStructure): + project_code: ProjectCode): super().__init__(name='ophys_experiment_metadata', value=self) self._experiment_container_id = experiment_container_id + self._imaging_plane = imaging_plane self._emission_lambda = emission_lambda - self._excitation_lambda = excitation_lambda self._field_of_view_shape = field_of_view_shape self._imaging_depth = imaging_depth - self._ophys_frame_rate = ophys_frame_rate self._project_code = project_code - self._targeted_structure = targeted_structure # project_code needs to be excluded from comparison # since it's only exposed internally @@ -80,31 +67,23 @@ def from_internal( lims_db: PostgresQueryMixin) -> "OphysExperimentMetadata": experiment_container_id = ExperimentContainerId.from_lims( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + imaging_plane = ImagingPlane.from_internal( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) emission_lambda = EmissionLambda(emission_lambda=520.0) - excitation_lambda = ExcitationLambda(excitation_lambda=910.0) field_of_view_shape = FieldOfViewShape.from_lims( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) imaging_depth = ImagingDepth.from_lims( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) - - sync_file = SyncFile.from_lims(ophys_experiment_id=ophys_experiment_id, - db=lims_db) - timestamps = StimulusTimestamps.from_sync_file(sync_file=sync_file) - ophys_frame_rate = OphysFrameRate.from_stimulus_file( - stimulus_timestamps=timestamps) project_code = ProjectCode.from_lims( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) - targeted_structure = TargetedStructure.from_lims( - ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + return cls( emission_lambda=emission_lambda, - excitation_lambda=excitation_lambda, + imaging_plane=imaging_plane, experiment_container_id=experiment_container_id, field_of_view_shape=field_of_view_shape, imaging_depth=imaging_depth, - ophys_frame_rate=ophys_frame_rate, project_code=project_code, - targeted_structure=targeted_structure ) @classmethod @@ -120,8 +99,8 @@ def emission_lambda(self) -> float: return self._emission_lambda.value @property - def excitation_lambda(self) -> float: - return self._excitation_lambda.value + def imaging_plane(self) -> ImagingPlane: + return self._imaging_plane # TODO rename to ophys_container_id @property @@ -129,12 +108,8 @@ def experiment_container_id(self) -> int: return self._experiment_container_id.value @property - def field_of_view_height(self) -> int: - return self._field_of_view_shape.height - - @property - def field_of_view_width(self) -> int: - return self._field_of_view_shape.width + def field_of_view_shape(self) -> FieldOfViewShape: + return self._field_of_view_shape @property def imaging_depth(self) -> int: @@ -145,10 +120,6 @@ def ophys_experiment_id(self) -> int: # TODO remove this. Should be at Ophys experiment class level return 0 - @property - def ophys_frame_rate(self) -> float: - return self._ophys_frame_rate.value - @property def ophys_session_id(self) -> int: # TODO this is at the wrong layer of abstraction. @@ -159,10 +130,6 @@ def ophys_session_id(self) -> int: def project_code(self) -> Optional[str]: return self._project_code.value - @property - def targeted_structure(self) -> str: - return self._targeted_structure.value - def to_dict(self) -> dict: """Returns dict representation of all properties in class""" vars_ = vars(OphysExperimentMetadata) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_frame_rate.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_frame_rate.py deleted file mode 100644 index fd00abe4b..000000000 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_frame_rate.py +++ /dev/null @@ -1,34 +0,0 @@ -from pynwb import NWBFile - -from allensdk.brain_observatory.behavior.data_objects import DataObject, \ - StimulusTimestamps -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .stimulus_file_readable_interface \ - import \ - StimulusFileReadableInterface - - -class OphysFrameRate(DataObject, StimulusFileReadableInterface, - NwbReadableInterface): - """Ophys frame rate""" - def __init__(self, ophys_frame_rate: float): - super().__init__(name="ophys_frame_rate", value=ophys_frame_rate) - - @classmethod - def from_stimulus_file( - cls, - stimulus_timestamps: StimulusTimestamps) -> "OphysFrameRate": - frame_rate = stimulus_timestamps.calc_frame_rate() - return cls(ophys_frame_rate=frame_rate) - - @classmethod - def from_nwb(cls, nwbfile: NWBFile) -> "OphysFrameRate": - ophys_module = nwbfile.processing['ophys'] - image_seg = ophys_module.data_interfaces['image_segmentation'] - imaging_plane = image_seg.plane_segmentations[ - 'cell_specimen_table'].imaging_plane - ophys_frame_rate = imaging_plane.imaging_rate - return cls(ophys_frame_rate=ophys_frame_rate) \ No newline at end of file diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/targeted_structure.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/targeted_structure.py deleted file mode 100644 index 14c8425a9..000000000 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/targeted_structure.py +++ /dev/null @@ -1,46 +0,0 @@ -from pynwb import NWBFile - -from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.internal.api import PostgresQueryMixin - - -class TargetedStructure(DataObject, LimsReadableInterface, - JsonReadableInterface, NwbReadableInterface): - """targeted structure (acronym) for an ophys experiment - (ex: "Visp")""" - def __init__(self, targeted_structure: str): - super().__init__(name='targeted_structure', value=targeted_structure) - - @classmethod - def from_lims(cls, ophys_experiment_id, - lims_db: PostgresQueryMixin) -> "TargetedStructure": - query = """ - SELECT st.acronym - FROM ophys_experiments oe - LEFT JOIN structures st ON st.id = oe.targeted_structure_id - WHERE oe.id = {}; - """.format(ophys_experiment_id) - targeted_structure = lims_db.fetchone(query, strict=True) - return cls(targeted_structure=targeted_structure) - - @classmethod - def from_json(cls, dict_repr: dict) -> "TargetedStructure": - return cls(targeted_structure=dict_repr['targeted_structure']) - - @classmethod - def from_nwb(cls, nwbfile: NWBFile) -> "TargetedStructure": - ophys_module = nwbfile.processing['ophys'] - image_seg = ophys_module.data_interfaces['image_segmentation'] - imaging_plane = image_seg.plane_segmentations[ - 'cell_specimen_table'].imaging_plane - targeted_structure = imaging_plane.location - return cls(targeted_structure=targeted_structure) From 611b72f26b01788691218bb77333a2a5bb398d86 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 21 Jun 2021 09:44:46 -0700 Subject: [PATCH 037/234] Add cell specimen table data object Complete missing data object methods Add BehaviorOphysMetadata data object which combines behavior,ophys --- .../behavior/behavior_session.py | 4 +- .../nwb_writable_interface.py | 2 +- .../data_objects/cell_specimen_table.py | 236 ++++++++++++++++++ .../behavior_metadata/behavior_metadata.py | 17 +- .../behavior_metadata/equipment_name.py | 2 +- .../behavior_metadata/session_type.py | 3 + .../metadata/behavior_ophys_metadata.py | 135 ++++++++++ .../mesoscope_experiment_metadata.py | 9 - .../ophys_experiment_metadata.py | 38 ++- 9 files changed, 417 insertions(+), 29 deletions(-) create mode 100644 allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index 07340c64c..136e31846 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -129,9 +129,7 @@ def from_internal(cls, behavior_session_id: int) -> "BehaviorSession": lims_db, behavior_session_id.value ) behavior_metadata = BehaviorMetadata.from_internal( - behavior_session_id=behavior_session_id, lims_db=lims_db, - stimulus_file=stimulus_file, - stimulus_timestamps=stimulus_timestamps + behavior_session_id=behavior_session_id, lims_db=lims_db ) return cls( api=BehaviorLimsApi(behavior_session_id.value), diff --git a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py index 83c4e5cf5..408be8f39 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py @@ -8,7 +8,7 @@ class NwbWritableInterface(abc.ABC): """Marks a data object as writable to NWB""" @abc.abstractmethod - def to_nwb(self, nwbfile: NWBFile) -> NWBFile: # pragma: no cover + def to_nwb(self, nwbfile: NWBFile, *args) -> NWBFile: # pragma: no cover """Given an already populated DataObject, return an pyNWB file object that had had DataObject data added. diff --git a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py new file mode 100644 index 000000000..84003848b --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py @@ -0,0 +1,236 @@ +import numpy as np +import pandas as pd +from pynwb import NWBFile, ProcessingModule +from pynwb.ophys import OpticalChannel, ImageSegmentation + +import allensdk.brain_observatory.roi_masks as roi +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .writable_interfaces.nwb_writable_interface import \ + NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_ophys_metadata import \ + BehaviorOphysMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata \ + .ophys_experiment_metadata.field_of_view_shape import \ + FieldOfViewShape +from allensdk.brain_observatory.nwb import CELL_SPECIMEN_COL_DESCRIPTIONS +from allensdk.internal.api import PostgresQueryMixin + + +class CellSpecimenTable(DataObject, LimsReadableInterface, + JsonReadableInterface, NwbReadableInterface, + NwbWritableInterface): + def __init__(self, cell_specimen_table: pd.DataFrame): + super().__init__(name='cell_specimen_table', value=cell_specimen_table) + + @classmethod + def from_lims(cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> "CellSpecimenTable": + def get_ophys_cell_segmentation_run_id() -> int: + """Get the ophys cell segmentation run id associated with an + ophys experiment id""" + query = """ + SELECT oseg.id + FROM ophys_experiments oe + JOIN ophys_cell_segmentation_runs oseg + ON oe.id = oseg.ophys_experiment_id + WHERE oseg.current = 't' + AND oe.id = {}; + """.format(ophys_experiment_id) + return lims_db.fetchone(query, strict=True) + + ophys_cell_seg_run_id = get_ophys_cell_segmentation_run_id() + query = """ + SELECT * + FROM cell_rois cr + WHERE cr.ophys_cell_segmentation_run_id = {}; + """.format(ophys_cell_seg_run_id) + initial_cs_table = pd.read_sql(query, lims_db.get_connection()) + cell_specimen_table = initial_cs_table.rename( + columns={'id': 'cell_roi_id', 'mask_matrix': 'roi_mask'}) + cell_specimen_table.drop(['ophys_experiment_id', + 'ophys_cell_segmentation_run_id'], + inplace=True, axis=1) + cell_specimen_table = cell_specimen_table.to_dict() + fov_shape = FieldOfViewShape.from_lims( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + cell_specimen_table = cls._postprocess( + cell_specimen_table=cell_specimen_table, fov_shape=fov_shape) + return cls(cell_specimen_table=cell_specimen_table) + + @classmethod + def from_json(cls, dict_repr: dict) -> "CellSpecimenTable": + cell_specimen_table = dict_repr['cell_specimen_table_dict'] + fov_shape = FieldOfViewShape.from_json(dict_repr=dict_repr) + cell_specimen_table = cls._postprocess( + cell_specimen_table=cell_specimen_table, fov_shape=fov_shape) + return cls(cell_specimen_table=cell_specimen_table) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile, + filter_invalid_rois=False) -> "CellSpecimenTable": + # NOTE: ROI masks are stored in full frame width and height arrays + df = nwbfile.processing[ + 'ophys'].data_interfaces[ + 'image_segmentation'].plane_segmentations[ + 'cell_specimen_table'].to_dataframe() + + # Because pynwb stores this field as "image_mask", it is renamed here + df = df.rename(columns={'image_mask': 'roi_mask'}) + + df.index.rename('cell_roi_id', inplace=True) + df['cell_specimen_id'] = [None if csid == -1 else csid + for csid in df['cell_specimen_id'].values] + + df.reset_index(inplace=True) + df.set_index('cell_specimen_id', inplace=True) + + if filter_invalid_rois: + df = df[df["valid_roi"]] + return cls(cell_specimen_table=df) + + def to_nwb(self, nwbfile: NWBFile, meta: BehaviorOphysMetadata) -> NWBFile: + """ + :param nwbfile + In-memory nwb file object + :param meta + Additional metadata not written to nwb yet, required to write + cell specimen table + """ + cell_roi_table = self.value.reset_index().set_index( + 'cell_roi_id') + metadata = nwbfile.lab_meta_data['metadata'] + imaging_plane_meta = meta.ophys_metadata.imaging_plane + + # Device: + device_name: str = metadata.equipment_name + if device_name.startswith("MESO"): + device_config = { + "name": device_name, + "description": "Allen Brain Observatory - Mesoscope 2P Rig" + } + else: + device_config = { + "name": device_name, + "description": "Allen Brain Observatory - Scientifica 2P Rig", + "manufacturer": "Scientifica" + } + nwbfile.create_device(**device_config) + device = nwbfile.get_device(device_name) + + # FOV: + fov_width = metadata.field_of_view_width + fov_height = metadata.field_of_view_height + imaging_plane_description = "{} field of view in {} at depth {} " \ + "um".format( + (fov_width, fov_height), + imaging_plane_meta.targeted_structure, + metadata.imaging_depth) + + # Optical Channel: + optical_channel = OpticalChannel( + name='channel_1', + description='2P Optical Channel', + emission_lambda=meta.ophys_metadata.emission_lambda) + + # Imaging Plane: + imaging_plane = nwbfile.create_imaging_plane( + name='imaging_plane_1', + optical_channel=optical_channel, + description=imaging_plane_description, + device=device, + excitation_lambda=imaging_plane_meta.excitation_lambda, + imaging_rate=imaging_plane_meta.ophys_frame_rate, + indicator=meta.behavior_metadata.subject_metadata.indicator, + location=imaging_plane_meta.targeted_structure) + + # Image Segmentation: + image_segmentation = ImageSegmentation(name="image_segmentation") + + if 'ophys' not in nwbfile.processing: + ophys_module = ProcessingModule('ophys', 'Ophys processing module') + nwbfile.add_processing_module(ophys_module) + else: + ophys_module = nwbfile.processing['ophys'] + + ophys_module.add_data_interface(image_segmentation) + + # Plane Segmentation: + plane_segmentation = image_segmentation.create_plane_segmentation( + name='cell_specimen_table', + description="Segmented rois", + imaging_plane=imaging_plane) + + for col_name in cell_roi_table.columns: + # the columns 'roi_mask', 'pixel_mask', and 'voxel_mask' are + # already defined in the nwb.ophys::PlaneSegmentation Object + if col_name not in ['id', 'mask_matrix', 'roi_mask', + 'pixel_mask', 'voxel_mask']: + # This builds the columns with name of column and description + # of column both equal to the column name in the cell_roi_table + plane_segmentation.add_column( + col_name, + CELL_SPECIMEN_COL_DESCRIPTIONS.get( + col_name, + "No Description Available")) + + # go through each roi and add it to the plan segmentation object + for cell_roi_id, table_row in cell_roi_table.iterrows(): + # NOTE: The 'roi_mask' in this cell_roi_table has already been + # processing by the function from + # allensdk.brain_observatory.behavior.session_apis.data_io + # .ophys_lims_api + # get_cell_specimen_table() method. As a result, the ROI is + # stored in + # an array that is the same shape as the FULL field of view of the + # experiment (e.g. 512 x 512). + mask = table_row.pop('roi_mask') + + csid = table_row.pop('cell_specimen_id') + table_row['cell_specimen_id'] = -1 if csid is None else csid + table_row['id'] = cell_roi_id + plane_segmentation.add_roi(image_mask=mask, **table_row.to_dict()) + + return nwbfile + + @staticmethod + def _postprocess(cell_specimen_table: dict, + fov_shape: FieldOfViewShape) -> pd.DataFrame: + """Converts raw cell_specimen_table dict to dataframe""" + cell_specimen_table = pd.DataFrame.from_dict( + cell_specimen_table).set_index( + 'cell_roi_id').sort_index() + fov_width = fov_shape.width + fov_height = fov_shape.height + + # Convert cropped ROI masks to uncropped versions + roi_mask_list = [] + for cell_roi_id, table_row in cell_specimen_table.iterrows(): + # Deserialize roi data into AllenSDK RoiMask object + curr_roi = roi.RoiMask(image_w=fov_width, image_h=fov_height, + label=None, mask_group=-1) + curr_roi.x = table_row['x'] + curr_roi.y = table_row['y'] + curr_roi.width = table_row['width'] + curr_roi.height = table_row['height'] + curr_roi.mask = np.array(table_row['roi_mask']) + roi_mask_list.append(curr_roi.get_mask_plane().astype(np.bool)) + + cell_specimen_table['roi_mask'] = roi_mask_list + cell_specimen_table = cell_specimen_table[ + sorted(cell_specimen_table.columns)] + + cell_specimen_table.index.rename('cell_roi_id', inplace=True) + cell_specimen_table.reset_index(inplace=True) + cell_specimen_table.set_index('cell_specimen_id', inplace=True) + return cell_specimen_table diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index 0764a0801..6a77630e9 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -218,14 +218,17 @@ def __init__(self, def from_internal( cls, behavior_session_id: BehaviorSessionId, - stimulus_file: StimulusFile, - stimulus_timestamps: StimulusTimestamps, lims_db: PostgresQueryMixin ) -> "BehaviorMetadata": subject_metadata = SubjectMetadata.from_lims( behavior_session_id=behavior_session_id, lims_db=lims_db) equipment_name = EquipmentName.from_lims( behavior_session_id=behavior_session_id.value, lims_db=lims_db) + + stimulus_file = StimulusFile.from_lims( + db=lims_db, behavior_session_id=behavior_session_id.value) + stimulus_timestamps = StimulusTimestamps.from_stimulus_file( + stimulus_file=stimulus_file) stimulus_frame_rate = StimulusFrameRate.from_stimulus_file( stimulus_timestamps=stimulus_timestamps) session_type = SessionType.from_stimulus_file( @@ -310,8 +313,8 @@ def stimulus_frame_rate(self) -> float: return self._stimulus_frame_rate.value @property - def session_type(self) -> str: - return self._session_type.value + def session_type(self) -> SessionType: + return self._session_type @property def date_of_acquisition(self) -> datetime: @@ -325,6 +328,10 @@ def behavior_session_uuid(self) -> Optional[uuid.UUID]: def behavior_session_id(self) -> int: return self._behavior_session_id.value + @property + def subject_metadata(self): + return self._subject_metadata + def to_dict(self) -> dict: """Returns dict representation of all properties in class""" vars_ = vars(BehaviorMetadata) @@ -343,7 +350,7 @@ def to_nwb(self, nwbfile: NWBFile) -> NWBFile: behavior_session_id=self.behavior_session_id, behavior_session_uuid=str(self.behavior_session_uuid), stimulus_frame_rate=self.stimulus_frame_rate, - session_type=self.session_type, + session_type=self.session_type.value, equipment_name=self.equipment_name ) nwbfile.add_lab_meta_data(nwb_metadata) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py index 79449c7dd..0763a4fc3 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py @@ -24,7 +24,7 @@ def __init__(self, equipment_name: str): @classmethod def from_json(cls, dict_repr: dict) -> "EquipmentName": - return cls(equipment_name=dict_repr["equipment_name"]) + return cls(equipment_name=dict_repr["rig_name"]) def to_json(self) -> dict: return {"eqipment_name": self.value} diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py index 72af578e2..882c6e6ed 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py @@ -38,3 +38,6 @@ def from_stimulus_file( def from_nwb(cls, nwbfile: NWBFile) -> "SessionType": metadata = nwbfile.lab_meta_data['metadata'] return cls(session_type=metadata.session_type) + + def is_mesoscope(self): + return self.value.startswith('MESO') diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py new file mode 100644 index 000000000..6de026ed3 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py @@ -0,0 +1,135 @@ +from typing import Union + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects import DataObject, \ + BehaviorSessionId, StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.internal_readable_interface import \ + InternalReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .writable_interfaces.nwb_writable_interface import \ + NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ + BehaviorMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.mesoscope_experiment_metadata\ + .mesoscope_experiment_metadata import \ + MesoscopeExperimentMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.ophys_experiment_metadata import \ + OphysExperimentMetadata +from allensdk.brain_observatory.behavior.schemas import \ + OphysBehaviorMetadataSchema +from allensdk.brain_observatory.nwb import load_pynwb_extension +from allensdk.internal.api import PostgresQueryMixin + + +class BehaviorOphysMetadata(DataObject, InternalReadableInterface, + JsonReadableInterface, NwbReadableInterface, + NwbWritableInterface): + def __init__(self, behavior_metadata: BehaviorMetadata, + ophys_metadata: Union[OphysExperimentMetadata, + MesoscopeExperimentMetadata]): + super().__init__(name='behavior_ophys_metadata', value=self) + + self._behavior_metadata = behavior_metadata + self._ophys_metadata = ophys_metadata + + @property + def behavior_metadata(self) -> BehaviorMetadata: + return self._behavior_metadata + + @property + def ophys_metadata(self) -> OphysExperimentMetadata: + return self._ophys_metadata + + @classmethod + def from_internal(cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> "BehaviorOphysMetadata": + behavior_session_id = BehaviorSessionId.from_lims( + ophys_experiment_id=ophys_experiment_id, db=lims_db) + + behavior_metadata = BehaviorMetadata.from_internal( + behavior_session_id=behavior_session_id, lims_db=lims_db) + + if behavior_metadata.session_type.is_mesoscope(): + ophys_metadata = MesoscopeExperimentMetadata.from_internal( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + else: + ophys_metadata = OphysExperimentMetadata.from_internal( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + + return cls(behavior_metadata=behavior_metadata, + ophys_metadata=ophys_metadata) + + @classmethod + def from_json(cls, dict_repr: dict) -> "BehaviorOphysMetadata": + behavior_metadata = BehaviorMetadata.from_json(dict_repr=dict_repr) + + if behavior_metadata.session_type.is_mesoscope(): + ophys_metadata = MesoscopeExperimentMetadata.from_json( + dict_repr=dict_repr) + else: + ophys_metadata = OphysExperimentMetadata.from_json( + dict_repr=dict_repr) + + return cls(behavior_metadata=behavior_metadata, + ophys_metadata=ophys_metadata) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorOphysMetadata": + behavior_metadata = BehaviorMetadata.from_nwb(nwbfile=nwbfile) + + if behavior_metadata.session_type.is_mesoscope(): + ophys_metadata = MesoscopeExperimentMetadata.from_nwb( + nwbfile=nwbfile) + else: + ophys_metadata = OphysExperimentMetadata.from_nwb( + nwbfile=nwbfile) + + return cls(behavior_metadata=behavior_metadata, + ophys_metadata=ophys_metadata) + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + self._behavior_metadata.subject_metadata.to_nwb(nwbfile=nwbfile) + OphysBehaviorMetadata = load_pynwb_extension( + OphysBehaviorMetadataSchema, 'ndx-aibs-behavior-ophys') + + behavior_meta = self._behavior_metadata + ophys_meta = self._ophys_metadata + + if isinstance(ophys_meta, MesoscopeExperimentMetadata): + imaging_plane_group = ophys_meta.imaging_plane_group + imaging_plane_group_count = ophys_meta.imaging_plane_group_count + else: + imaging_plane_group_count = 0 + imaging_plane_group = -1 + + nwb_metadata = OphysBehaviorMetadata( + name='metadata', + ophys_session_id=ophys_meta.ophys_session_id, + field_of_view_width=ophys_meta.field_of_view_shape.width, + field_of_view_height=ophys_meta.field_of_view_shape.height, + imaging_plane_group=imaging_plane_group, + imaging_plane_group_count=imaging_plane_group_count, + stimulus_frame_rate=behavior_meta.stimulus_frame_rate, + experiment_container_id=ophys_meta.experiment_container_id, + ophys_experiment_id=ophys_meta.ophys_experiment_id, + session_type=behavior_meta.session_type.value, + equipment_name=behavior_meta.equipment_name, + imaging_depth=ophys_meta.imaging_depth, + behavior_session_uuid=str(behavior_meta.behavior_session_uuid), + behavior_session_id=behavior_meta.behavior_session_id + ) + nwbfile.add_lab_meta_data(nwb_metadata) + + return nwbfile diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py index 3b61d3ee4..dee35c9aa 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py @@ -1,14 +1,5 @@ from pynwb import NWBFile -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.internal_readable_interface import \ - InternalReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.imaging_plane import \ ImagingPlane diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py index d1d76a3b0..84d02718c 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py @@ -2,9 +2,7 @@ from pynwb import NWBFile -from allensdk.brain_observatory.behavior.data_files import SyncFile -from allensdk.brain_observatory.behavior.data_objects import DataObject, \ - StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects import DataObject from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.internal_readable_interface import \ InternalReadableInterface @@ -38,17 +36,13 @@ class OphysExperimentMetadata(DataObject, InternalReadableInterface, JsonReadableInterface, NwbReadableInterface): """Container class for behavior ophys metadata""" - # def __init__(self, extractor: BehaviorOphysDataExtractorBase, - # stimulus_timestamps: np.ndarray, - # ophys_timestamps: np.ndarray, - # behavior_stimulus_file: dict): def __init__(self, experiment_container_id: ExperimentContainerId, imaging_plane: ImagingPlane, emission_lambda: EmissionLambda, field_of_view_shape: FieldOfViewShape, imaging_depth: ImagingDepth, - project_code: ProjectCode): + project_code: Optional[ProjectCode] = None): super().__init__(name='ophys_experiment_metadata', value=self) self._experiment_container_id = experiment_container_id self._imaging_plane = imaging_plane @@ -88,11 +82,35 @@ def from_internal( @classmethod def from_json(cls, dict_repr: dict) -> "OphysExperimentMetadata": - pass + experiment_container_id = ExperimentContainerId.from_json( + dict_repr=dict_repr) + imaging_plane = ImagingPlane.from_json(dict_repr=dict_repr) + emission_lambda = EmissionLambda() + field_of_view_shape = FieldOfViewShape.from_json(dict_repr=dict_repr) + imaging_depth = ImagingDepth.from_json(dict_repr=dict_repr) + return cls( + experiment_container_id=experiment_container_id, + imaging_plane=imaging_plane, + emission_lambda=emission_lambda, + field_of_view_shape=field_of_view_shape, + imaging_depth=imaging_depth + ) @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "OphysExperimentMetadata": - pass + experiment_container_id = ExperimentContainerId.from_nwb( + nwbfile=nwbfile) + imaging_plane = ImagingPlane.from_nwb(nwbfile=nwbfile) + emission_lambda = EmissionLambda() + field_of_view_shape = FieldOfViewShape.from_nwb(nwbfile=nwbfile) + imaging_depth = ImagingDepth.from_nwb(nwbfile=nwbfile) + return cls( + experiment_container_id=experiment_container_id, + imaging_plane=imaging_plane, + emission_lambda=emission_lambda, + field_of_view_shape=field_of_view_shape, + imaging_depth=imaging_depth + ) @property def emission_lambda(self) -> float: From e5400593a03a1374c5194e04803cd55be18beb37 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 21 Jun 2021 12:58:01 -0700 Subject: [PATCH 038/234] adds ophys experiment id --- .../data_objects/metadata/behavior_ophys_metadata.py | 3 +-- .../ophys_experiment_metadata.py | 10 +++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py index 6de026ed3..116ce4358 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py @@ -2,9 +2,8 @@ from pynwb import NWBFile -from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject, \ - BehaviorSessionId, StimulusTimestamps + BehaviorSessionId from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.internal_readable_interface import \ InternalReadableInterface diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py index 84d02718c..2317d1439 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py @@ -35,8 +35,9 @@ class OphysExperimentMetadata(DataObject, InternalReadableInterface, JsonReadableInterface, NwbReadableInterface): - """Container class for behavior ophys metadata""" + """Container class for ophys experiment metadata""" def __init__(self, + ophys_experiment_id: int, experiment_container_id: ExperimentContainerId, imaging_plane: ImagingPlane, emission_lambda: EmissionLambda, @@ -44,6 +45,7 @@ def __init__(self, imaging_depth: ImagingDepth, project_code: Optional[ProjectCode] = None): super().__init__(name='ophys_experiment_metadata', value=self) + self._ophys_experiment_id = ophys_experiment_id self._experiment_container_id = experiment_container_id self._imaging_plane = imaging_plane self._emission_lambda = emission_lambda @@ -72,6 +74,7 @@ def from_internal( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) return cls( + ophys_experiment_id=ophys_experiment_id, emission_lambda=emission_lambda, imaging_plane=imaging_plane, experiment_container_id=experiment_container_id, @@ -84,11 +87,13 @@ def from_internal( def from_json(cls, dict_repr: dict) -> "OphysExperimentMetadata": experiment_container_id = ExperimentContainerId.from_json( dict_repr=dict_repr) + ophys_experiment_id = dict_repr['ophys_experiment_id'] imaging_plane = ImagingPlane.from_json(dict_repr=dict_repr) emission_lambda = EmissionLambda() field_of_view_shape = FieldOfViewShape.from_json(dict_repr=dict_repr) imaging_depth = ImagingDepth.from_json(dict_repr=dict_repr) return cls( + ophys_experiment_id=ophys_experiment_id, experiment_container_id=experiment_container_id, imaging_plane=imaging_plane, emission_lambda=emission_lambda, @@ -98,6 +103,7 @@ def from_json(cls, dict_repr: dict) -> "OphysExperimentMetadata": @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "OphysExperimentMetadata": + ophys_experiment_id = nwbfile.identifier experiment_container_id = ExperimentContainerId.from_nwb( nwbfile=nwbfile) imaging_plane = ImagingPlane.from_nwb(nwbfile=nwbfile) @@ -105,6 +111,7 @@ def from_nwb(cls, nwbfile: NWBFile) -> "OphysExperimentMetadata": field_of_view_shape = FieldOfViewShape.from_nwb(nwbfile=nwbfile) imaging_depth = ImagingDepth.from_nwb(nwbfile=nwbfile) return cls( + ophys_experiment_id=ophys_experiment_id, experiment_container_id=experiment_container_id, imaging_plane=imaging_plane, emission_lambda=emission_lambda, @@ -142,6 +149,7 @@ def ophys_experiment_id(self) -> int: def ophys_session_id(self) -> int: # TODO this is at the wrong layer of abstraction. # Should be at ophys session level + # (need to create ophys session class) return 0 @property From 8b25dc4cb8730dadd219a4eaacc42f182dba68d3 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 21 Jun 2021 13:07:03 -0700 Subject: [PATCH 039/234] adds ophys session id --- .../ophys_experiment_metadata.py | 17 ++++++-- .../ophys_session_id.py | 41 +++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_session_id.py diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py index 2317d1439..e052f8caf 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py @@ -27,6 +27,9 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.imaging_plane import \ ImagingPlane +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.ophys_session_id import \ + OphysSessionId from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.project_code import \ ProjectCode @@ -38,6 +41,7 @@ class OphysExperimentMetadata(DataObject, InternalReadableInterface, """Container class for ophys experiment metadata""" def __init__(self, ophys_experiment_id: int, + ophys_session_id: OphysSessionId, experiment_container_id: ExperimentContainerId, imaging_plane: ImagingPlane, emission_lambda: EmissionLambda, @@ -46,6 +50,7 @@ def __init__(self, project_code: Optional[ProjectCode] = None): super().__init__(name='ophys_experiment_metadata', value=self) self._ophys_experiment_id = ophys_experiment_id + self._ophys_session_id = ophys_session_id self._experiment_container_id = experiment_container_id self._imaging_plane = imaging_plane self._emission_lambda = emission_lambda @@ -61,6 +66,8 @@ def __init__(self, def from_internal( cls, ophys_experiment_id: int, lims_db: PostgresQueryMixin) -> "OphysExperimentMetadata": + ophys_session_id = OphysSessionId.from_lims( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) experiment_container_id = ExperimentContainerId.from_lims( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) imaging_plane = ImagingPlane.from_internal( @@ -75,6 +82,7 @@ def from_internal( return cls( ophys_experiment_id=ophys_experiment_id, + ophys_session_id=ophys_session_id, emission_lambda=emission_lambda, imaging_plane=imaging_plane, experiment_container_id=experiment_container_id, @@ -85,6 +93,7 @@ def from_internal( @classmethod def from_json(cls, dict_repr: dict) -> "OphysExperimentMetadata": + ophys_session_id = OphysSessionId.from_json(dict_repr=dict_repr) experiment_container_id = ExperimentContainerId.from_json( dict_repr=dict_repr) ophys_experiment_id = dict_repr['ophys_experiment_id'] @@ -94,6 +103,7 @@ def from_json(cls, dict_repr: dict) -> "OphysExperimentMetadata": imaging_depth = ImagingDepth.from_json(dict_repr=dict_repr) return cls( ophys_experiment_id=ophys_experiment_id, + ophys_session_id=ophys_session_id, experiment_container_id=experiment_container_id, imaging_plane=imaging_plane, emission_lambda=emission_lambda, @@ -104,6 +114,7 @@ def from_json(cls, dict_repr: dict) -> "OphysExperimentMetadata": @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "OphysExperimentMetadata": ophys_experiment_id = nwbfile.identifier + ophys_session_id = OphysSessionId.from_nwb(nwbfile=nwbfile) experiment_container_id = ExperimentContainerId.from_nwb( nwbfile=nwbfile) imaging_plane = ImagingPlane.from_nwb(nwbfile=nwbfile) @@ -112,6 +123,7 @@ def from_nwb(cls, nwbfile: NWBFile) -> "OphysExperimentMetadata": imaging_depth = ImagingDepth.from_nwb(nwbfile=nwbfile) return cls( ophys_experiment_id=ophys_experiment_id, + ophys_session_id=ophys_session_id, experiment_container_id=experiment_container_id, imaging_plane=imaging_plane, emission_lambda=emission_lambda, @@ -142,15 +154,14 @@ def imaging_depth(self) -> int: @property def ophys_experiment_id(self) -> int: - # TODO remove this. Should be at Ophys experiment class level - return 0 + return self._ophys_experiment_id @property def ophys_session_id(self) -> int: # TODO this is at the wrong layer of abstraction. # Should be at ophys session level # (need to create ophys session class) - return 0 + return self._ophys_session_id.value @property def project_code(self) -> Optional[str]: diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_session_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_session_id.py new file mode 100644 index 000000000..f29e9060f --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_session_id.py @@ -0,0 +1,41 @@ +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.nwb_readable_interface import \ + NwbReadableInterface +from allensdk.internal.api import PostgresQueryMixin + + +class OphysSessionId(DataObject, LimsReadableInterface, + JsonReadableInterface, NwbReadableInterface): + """"Ophys session id""" + def __init__(self, session_id: int): + super().__init__(name='session_id', + value=session_id) + + @classmethod + def from_lims(cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> "OphysSessionId": + query = """ + SELECT oe.ophys_session_id + FROM ophys_experiments oe + WHERE id = {}; + """.format(ophys_experiment_id) + session_id = lims_db.fetchone(query, strict=False) + return cls(session_id=session_id) + + @classmethod + def from_json(cls, dict_repr: dict) -> "OphysSessionId": + return cls(session_id=dict_repr['ophys_session_id']) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "OphysSessionId": + metadata = nwbfile.lab_meta_data['metadata'] + return cls(session_id=metadata.ophys_session_id) From 036add1e368a84b048c2cdc1038ac70a5295e029 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 21 Jun 2021 13:57:54 -0700 Subject: [PATCH 040/234] refactors test_behavior_metadata --- .../subject_metadata/reporter_line.py | 7 +- .../subject_metadata/subject_metadata.py | 2 +- .../behavior/test_behavior_metadata.py | 277 ++++-------------- 3 files changed, 68 insertions(+), 218 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py index e807dc7e5..7ec7d0877 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py @@ -1,5 +1,5 @@ import warnings -from typing import Optional, List +from typing import Optional, List, Union from pynwb import NWBFile @@ -61,7 +61,7 @@ def from_nwb(cls, nwbfile: NWBFile) -> "ReporterLine": return cls(reporter_line=nwbfile.subject.reporter_line) @staticmethod - def _parse(reporter_line: Optional[List[str]], + def _parse(reporter_line: Union[Optional[List[str]], str], warn=False) -> Optional[str]: """There can be multiple reporter lines, so it is returned from LIMS as a list. But there shouldn't be more than 1 for behavior. This @@ -99,8 +99,7 @@ def _parse(reporter_line: Optional[List[str]], return reporter_line[0] - @property - def indicator(self, warn=False) -> Optional[str]: + def parse_indicator(self, warn=False) -> Optional[str]: """Parses indicator from reporter""" reporter_line = self.value reporter_substring_indicator_map = { diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py index 4b781ec5d..15d2fea84 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py @@ -155,7 +155,7 @@ def reporter_line(self) -> Optional[str]: @property def indicator(self) -> Optional[str]: - return self._reporter_line.indicator + return self._reporter_line.parse_indicator(warn=True) @property def full_genotype(self) -> str: diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py b/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py index e1ca6e79e..3f2514a29 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py @@ -6,10 +6,23 @@ import pandas as pd import pytz +from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_metadata import ( description_dict, get_task_parameters, get_expt_description, BehaviorMetadata) +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.date_of_acquisition import \ + DateOfAcquisition +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.age import \ + Age +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.full_genotype import \ + FullGenotype +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.reporter_line import \ + ReporterLine @pytest.mark.parametrize("data, expected", @@ -325,94 +338,34 @@ def test_get_expt_description_raises_with_invalid_session_type(session_type): get_expt_description(session_type) -def test_cre_line(monkeypatch): +def test_cre_line(): """Tests that cre_line properly parsed from driver_line""" - with monkeypatch.context() as ctx: - def dummy_init(self): - pass - - def full_genotype(self): - return 'Sst-IRES-Cre/wt;Ai148(TIT2L-GC6f-ICL-tTA2)/wt' - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - ctx.setattr(BehaviorMetadata, - 'full_genotype', - property(full_genotype)) - - metadata = BehaviorMetadata() - - assert metadata.cre_line == 'Sst-IRES-Cre' + fg = FullGenotype( + full_genotype='Sst-IRES-Cre/wt;Ai148(TIT2L-GC6f-ICL-tTA2)/wt') + assert fg.parse_cre_line() == 'Sst-IRES-Cre' -def test_cre_line_bad_full_genotype(monkeypatch): +def test_cre_line_bad_full_genotype(): """Test that cre_line is None and no error raised""" - with monkeypatch.context() as ctx: - def dummy_init(self): - pass + fg = FullGenotype(full_genotype='foo') - def full_genotype(self): - return 'foo' + with pytest.warns(UserWarning) as record: + cre_line = fg.parse_cre_line(warn=True) + assert cre_line is None + assert str(record[0].message) == 'Unable to parse cre_line from ' \ + 'full_genotype' - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - ctx.setattr(BehaviorMetadata, - 'full_genotype', - property(full_genotype)) - metadata = BehaviorMetadata() - - with pytest.warns(UserWarning) as record: - cre_line = metadata.cre_line - assert cre_line is None - assert str(record[0].message) == 'Unable to parse cre_line from ' \ - 'full_genotype' - - -def test_reporter_line(monkeypatch): +def test_reporter_line(): """Test that reporter line properly parsed from list""" + reporter_line = ReporterLine._parse(reporter_line=['foo']) + assert reporter_line == 'foo' - class MockExtractor: - def get_reporter_line(self): - return ['foo'] - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - assert metadata.reporter_line == 'foo' - - -def test_reporter_line_str(monkeypatch): +def test_reporter_line_str(): """Test that reporter line returns itself if str""" - - class MockExtractor: - def get_reporter_line(self): - return 'foo' - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - - assert metadata.reporter_line == 'foo' + reporter_line = ReporterLine._parse(reporter_line='foo') + assert reporter_line == 'foo' @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( @@ -422,52 +375,20 @@ def dummy_init(self): ([], 'Error parsing reporter line. The array is empty', None) ) ) -def test_reporter_edge_cases(monkeypatch, input_reporter_line, warning_msg, +def test_reporter_edge_cases(input_reporter_line, warning_msg, expected): """Test reporter line edge cases""" + with pytest.warns(UserWarning) as record: + reporter_line = ReporterLine._parse(reporter_line=input_reporter_line, + warn=True) + assert reporter_line == expected + assert str(record[0].message) == warning_msg - class MockExtractor: - def get_reporter_line(self): - return input_reporter_line - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - metadata = BehaviorMetadata() - - with pytest.warns(UserWarning) as record: - reporter_line = metadata.reporter_line - - assert reporter_line == expected - assert str(record[0].message) == warning_msg - - -def test_age_in_days(monkeypatch): +def test_age_in_days(): """Test that age_in_days properly parsed from age""" - - class MockExtractor: - def get_age(self): - return 'P123' - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - - assert metadata.age_in_days == 123 + age = Age._age_code_to_days(age='P123') + assert age == 123 @pytest.mark.parametrize("input_age, warning_msg, expected", ( @@ -480,28 +401,11 @@ def dummy_init(self): def test_age_in_days_edge_cases(monkeypatch, input_age, warning_msg, expected): """Test age in days edge cases""" + with pytest.warns(UserWarning) as record: + age_in_days = Age._age_code_to_days(age=input_age, warn=True) - class MockExtractor: - def get_age(self): - return input_age - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - - with pytest.warns(UserWarning) as record: - age_in_days = metadata.age_in_days - - assert age_in_days is None - assert str(record[0].message) == warning_msg + assert age_in_days is None + assert str(record[0].message) == warning_msg @pytest.mark.parametrize("test_params, expected_warn_msg", [ @@ -541,102 +445,49 @@ def dummy_init(self): }, "Could not parse the acquisition datetime *"), ]) -def test_get_date_of_acquisition(monkeypatch, tmp_path, test_params, +def test_get_date_of_acquisition(tmp_path, test_params, expected_warn_msg): mock_session_id = test_params["behavior_session_id"] pkl_save_path = tmp_path / f"mock_pkl_{mock_session_id}.pkl" with open(pkl_save_path, 'wb') as handle: pickle.dump({"start_time": test_params['pkl_expt_date']}, handle) - behavior_stimulus_file = pd.read_pickle(pkl_save_path) tz = pytz.timezone("America/Los_Angeles") extractor_expt_date = tz.localize( test_params['extractor_expt_date']).astimezone(pytz.utc) - class MockExtractor(): - def get_date_of_acquisition(self): - return extractor_expt_date - - def get_behavior_session_id(self): - return test_params['behavior_session_id'] - - def get_behavior_stimulus_file(self): - return pkl_save_path - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self, extractor, behavior_stimulus_file): - self._extractor = extractor - self._behavior_stimulus_file = behavior_stimulus_file + stimulus_file = StimulusFile(filepath=pkl_save_path) + obt_date = DateOfAcquisition( + date_of_acquisition=extractor_expt_date) - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) + if expected_warn_msg: + with pytest.warns(Warning, match=expected_warn_msg): + obt_date.validate( + stimulus_file=stimulus_file, + behavior_session_id=test_params['behavior_session_id']) - metadata = BehaviorMetadata( - extractor=extractor, - behavior_stimulus_file=behavior_stimulus_file) + assert obt_date.value == extractor_expt_date - if expected_warn_msg: - with pytest.warns(Warning, match=expected_warn_msg): - obt_date = metadata.date_of_acquisition - else: - obt_date = metadata.date_of_acquisition - assert obt_date == extractor_expt_date - - -def test_indicator(monkeypatch): +def test_indicator(): """Test that indicator is parsed from full_genotype""" - - class MockExtractor: - def get_reporter_line(self): - return 'Ai148(TIT2L-GC6f-ICL-tTA2)' - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - - assert metadata.indicator == 'GCaMP6f' + reporter_line = ReporterLine(reporter_line='Ai148(TIT2L-GC6f-ICL-tTA2)') + assert reporter_line.parse_indicator() == 'GCaMP6f' @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( - (None, 'Error parsing reporter line. It is null.', None), + (None, 'Could not parse indicator from reporter because there is no ' + 'reporter', None), ('foo', 'Could not parse indicator from reporter because none' 'of the expected substrings were found in the reporter', None) ) ) -def test_indicator_edge_cases(monkeypatch, input_reporter_line, warning_msg, +def test_indicator_edge_cases(input_reporter_line, warning_msg, expected): """Test indicator parsing edge cases""" - - class MockExtractor: - def get_reporter_line(self): - return input_reporter_line - - extractor = MockExtractor() - - with monkeypatch.context() as ctx: - def dummy_init(self): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - - metadata = BehaviorMetadata() - - with pytest.warns(UserWarning) as record: - indicator = metadata.indicator - assert indicator is expected - assert str(record[0].message) == warning_msg + with pytest.warns(UserWarning) as record: + reporter_line = ReporterLine(reporter_line=input_reporter_line) + indicator = reporter_line.parse_indicator(warn=True) + assert indicator is expected + assert str(record[0].message) == warning_msg From a4a4c6767c998495496bcaa0a4f7e3dc8a28d93d Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 21 Jun 2021 14:48:32 -0700 Subject: [PATCH 041/234] refactors test_behavior_lims_api --- .../behavior_metadata/date_of_acquisition.py | 12 ++++-- .../behavior/test_behavior_lims_api.py | 43 +++++++++++-------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py index d881051dc..76cea636d 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py @@ -30,10 +30,9 @@ def __init__(self, date_of_acquisition: float): @classmethod def from_json(cls, dict_repr: dict) -> "DateOfAcquisition": - tz = pytz.timezone("America/Los_Angeles") doa = dict_repr['date_of_acquisition'] - doa = tz.localize(datetime.strptime(doa, "%Y-%m-%d %H:%M:%S")) - doa = doa.astimezone(pytz.utc) + doa = datetime.strptime(doa, "%Y-%m-%d %H:%M:%S") + doa = cls.to_utc(date_of_acquisition=doa) return cls(date_of_acquisition=doa) def to_json(self) -> dict: @@ -50,7 +49,7 @@ def from_lims( """.format(behavior_session_id) experiment_date = lims_db.fetchone(query, strict=True) - experiment_date = pytz.utc.localize(experiment_date) + experiment_date = cls.to_utc(date_of_acquisition=experiment_date) return cls(date_of_acquisition=experiment_date) @classmethod @@ -94,3 +93,8 @@ def validate(self, stimulus_file: StimulusFile, f"{stimulus_file.filepath}" ) return self + + @staticmethod + def to_utc(date_of_acquisition: datetime): + return pytz.utc.localize(dt=date_of_acquisition) + diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py b/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py index 77a3891cb..a64d8ae21 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py @@ -1,7 +1,9 @@ +import json import math import pickle import tempfile from datetime import datetime +from pathlib import Path from uuid import UUID import numpy as np @@ -11,6 +13,7 @@ from allensdk import OneResultExpectedError from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects import StimulusTimestamps from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_metadata import \ BehaviorMetadata @@ -132,7 +135,7 @@ def get_foraging_id(self) -> str: class MockBehaviorLimsApi(BehaviorLimsApi): - def _behavior_stimulus_file(self): + def _behavior_stimulus_file(self) -> StimulusFile: data = { "items": { "behavior": { @@ -166,7 +169,7 @@ def _behavior_stimulus_file(self): f.seek(0) file = StimulusFile.from_json( dict_repr={'behavior_stimulus_file': f.name}) - return file + return file def get_running_acquisition_df(self, lowpass=True): return pd.DataFrame( @@ -216,9 +219,11 @@ def get_running_acquisition_df(self, lowpass=True): # Does not include test for get_metadata since it just collects data from # methods covered in other unit tests, or data derived from sql queries. def test_get_stimulus_timestamps(MockBehaviorLimsApi): - api = MockBehaviorLimsApi + stim_file = MockBehaviorLimsApi._behavior_stimulus_file() + stimulus_timestamps = StimulusTimestamps.from_stimulus_file( + stimulus_file=stim_file) expected = np.array([0.016 * i for i in range(11)]) - assert np.allclose(expected, api.get_stimulus_timestamps()) + assert np.allclose(expected, stimulus_timestamps.value) def test_get_licks(MockBehaviorLimsApi): @@ -228,26 +233,26 @@ def test_get_licks(MockBehaviorLimsApi): pd.testing.assert_frame_equal(expected, api.get_licks()) -def test_get_behavior_session_uuid(MockBehaviorLimsApi, monkeypatch): - with monkeypatch.context() as ctx: - def dummy_init(self, extractor, behavior_stimulus_file): - self._extractor = extractor - self._behavior_stimulus_file = behavior_stimulus_file - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_init) - stimulus_file = MockBehaviorLimsApi._behavior_stimulus_file() - uuid = BehaviorSessionUUID.from_stimulus_file( - stimulus_file=stimulus_file) - +def test_get_behavior_session_uuid(MockBehaviorLimsApi): + stimulus_file = MockBehaviorLimsApi._behavior_stimulus_file() + uuid = BehaviorSessionUUID.from_stimulus_file( + stimulus_file=stimulus_file) expected = UUID('138531ab-fe59-4523-9154-07c8d97bbe03') assert expected == uuid.value def test_get_stimulus_frame_rate(MockBehaviorLimsApi): - api = MockBehaviorLimsApi - assert 62.0 == api.get_stimulus_frame_rate() + stim_file = MockBehaviorLimsApi._behavior_stimulus_file() + stimulus_timestamps = StimulusTimestamps.from_stimulus_file( + stimulus_file=stim_file) + assert 62.0 == stimulus_timestamps.calc_frame_rate() + + +def test_get_date_of_acquisition(): + expected = datetime(2019, 9, 26, 16, tzinfo=pytz.UTC) + doa = datetime(2019, 9, 26, 16) + actual = DateOfAcquisition.to_utc(date_of_acquisition=doa) + assert expected == actual def test_get_running_speed(MockBehaviorLimsApi): From 88f958a838ad9dff8338d4b904487a2eb84c11ea Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 21 Jun 2021 15:32:02 -0700 Subject: [PATCH 042/234] adds attrs and methods to ignore --- allensdk/brain_observatory/behavior/behavior_session.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index 136e31846..8245ded18 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -223,6 +223,11 @@ def list_data_attributes_and_methods(self) -> List[str]: } attrs_and_methods_to_ignore.update(dir(ParamsMixin)) attrs_and_methods_to_ignore.update(dir(LazyPropertyMixin)) + attrs_and_methods_to_ignore.update(dir(InternalReadableInterface)) + attrs_and_methods_to_ignore.update(dir(NwbReadableInterface)) + attrs_and_methods_to_ignore.update(dir(NwbWritableInterface)) + attrs_and_methods_to_ignore.update(dir(JsonWritableInterface)) + attrs_and_methods_to_ignore.update(dir(DataObject)) class_dir = dir(self) attrs_and_methods = [ r for r in class_dir From 826fac2187f2d82fb0fab669c53a9788c814e3f4 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 22 Jun 2021 09:05:01 -0700 Subject: [PATCH 043/234] Adds comparison for data object; refactors test_behavior_nwb --- .../data_objects/base/_data_object_abc.py | 83 ++++++++++++++++++- .../behavior_metadata/behavior_metadata.py | 37 +-------- .../mesoscope_experiment_metadata.py | 13 +++ .../brain_observatory/comparison_utils.py | 60 ++++++++++++++ .../brain_observatory/session_api_utils.py | 60 +------------- .../brain_observatory/behavior/conftest.py | 81 ++++++++++++++---- .../test_behavior_ophys_experiment.py | 5 +- .../behavior/test_write_behavior_nwb.py | 22 ++--- 8 files changed, 235 insertions(+), 126 deletions(-) create mode 100644 allensdk/brain_observatory/comparison_utils.py diff --git a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py index a411e52e5..c159e4797 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py @@ -1,8 +1,11 @@ import abc -from typing import Any +from collections import deque +from typing import Any, Optional, Set from pynwb import NWBFile +from allensdk.brain_observatory.comparison_utils import compare_fields + class DataObject(abc.ABC): """An abstract class that prototypes properties that represent a @@ -12,9 +15,20 @@ class DataObject(abc.ABC): data sources and sinks (e.g. LIMS, JSON, NWB). """ - def __init__(self, name: str, value: Any): + def __init__(self, name: str, value: Any, + exclude_from_equals: Optional[Set] = None): + """ + :param name + Name + :param value + Value + :param exclude_from_equals + Optional set which will exclude these properties from comparison + checks to another DataObject + """ self._name = name self._value = value + self._exclude_from_equals = exclude_from_equals @property def name(self) -> str: @@ -23,3 +37,68 @@ def name(self) -> str: @property def value(self) -> Any: return self._value + + @classmethod + def _get_vars(cls): + return vars(cls) + + def to_dict(self): + res = {} + q = deque([(name, value, []) for name, value in + self._get_properties().items()]) + while q: + name, value, path = q.popleft() + if isinstance(value, DataObject): + cur = res + for p in path: + cur = cur[p] + cur[name] = {} + path.append(name) + values = [(name, value, path) for name, value in + value._get_properties().items()] + if not values: + q.append((name, value._value, path)) + else: + for v in values: + q.append(v) + else: + cur = res + for p in path: + cur = cur[p] + cur[name] = value + + return res + + def _get_properties(self): + """Returns all property names and values""" + vars_ = self._get_vars() + return {name: getattr(self, name) for name, value in vars_.items() + if isinstance(value, property)} + + def __eq__(self, other: "DataObject"): + if type(self) != type(other): + msg = f'Do not know how to compare with type {type(other)}' + raise NotImplementedError(msg) + + d_self = self.to_dict() + d_other = other.to_dict() + + # if not isinstance(self._value, DataObject): + # properties_self['value'] = self._value + # properties_other['value'] = other._value + # + # properties_self['name'] = self._name + # properties_other['name'] = other._name + + for p in d_self: + if p in self._exclude_from_equals: + continue + + x1 = d_self[p] + x2 = d_other[p] + + try: + compare_fields(x1=x1, x2=x2) + except AssertionError: + return False + return True diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index 6a77630e9..1922fd2c1 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -47,7 +47,7 @@ SubjectMetadata from allensdk.brain_observatory.behavior.schemas import BehaviorMetadataSchema from allensdk.brain_observatory.nwb import load_pynwb_extension -from allensdk.brain_observatory.session_api_utils import compare_session_fields +from allensdk.brain_observatory.comparison_utils import compare_fields from allensdk.internal.api import PostgresQueryMixin description_dict = { @@ -332,11 +332,6 @@ def behavior_session_id(self) -> int: def subject_metadata(self): return self._subject_metadata - def to_dict(self) -> dict: - """Returns dict representation of all properties in class""" - vars_ = vars(BehaviorMetadata) - return self._get_properties(vars_=vars_) - def to_json(self) -> dict: pass @@ -357,32 +352,6 @@ def to_nwb(self, nwbfile: NWBFile) -> NWBFile: return nwbfile - def _get_properties(self, vars_: dict): - """Returns all property names and values""" - return {name: getattr(self, name) for name, value in vars_.items() - if isinstance(value, property)} - - def __eq__(self, other): - if not isinstance(other, (BehaviorMetadata, dict)): - msg = f'Do not know how to compare with type {type(other)}' - raise NotImplementedError(msg) - - properties_self = self.to_dict() - - if isinstance(other, dict): - properties_other = other - else: - properties_other = other.to_dict() - - for p in properties_self: - if p in self._exclude_from_equals: - continue - - x1 = properties_self[p] - x2 = properties_other[p] + def __dict__(self): + props = self._get_properties() - try: - compare_session_fields(x1=x1, x2=x2) - except AssertionError: - return False - return True diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py index dee35c9aa..2e4d182c6 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py @@ -22,6 +22,9 @@ .ophys_experiment_metadata.mesoscope_experiment_metadata\ .imaging_plane_group import \ ImagingPlaneGroup +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.ophys_session_id import \ + OphysSessionId from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.project_code import \ ProjectCode @@ -30,6 +33,8 @@ class MesoscopeExperimentMetadata(OphysExperimentMetadata): def __init__(self, + ophys_experiment_id: int, + ophys_session_id: OphysSessionId, experiment_container_id: ExperimentContainerId, emission_lambda: EmissionLambda, imaging_plane: ImagingPlane, @@ -38,6 +43,8 @@ def __init__(self, imaging_plane_group: ImagingPlaneGroup, project_code: ProjectCode): super().__init__( + ophys_experiment_id=ophys_experiment_id, + ophys_session_id=ophys_session_id, experiment_container_id=experiment_container_id, emission_lambda=emission_lambda, imaging_plane=imaging_plane, @@ -56,6 +63,8 @@ def from_internal( imaging_plane_group = ImagingPlaneGroup.from_lims( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) return cls( + ophys_experiment_id=ophys_experiment_metadata.ophys_experiment_id, + ophys_session_id=ophys_experiment_metadata._ophys_session_id, experiment_container_id= ophys_experiment_metadata._experiment_container_id, emission_lambda=ophys_experiment_metadata._emission_lambda, @@ -71,6 +80,8 @@ def from_json(cls, dict_repr: dict) -> "MesoscopeExperimentMetadata": ophys_experiment_metadata = super().from_json(dict_repr=dict_repr) imaging_plane_group = ImagingPlaneGroup.from_json(dict_repr=dict_repr) return cls( + ophys_experiment_id=ophys_experiment_metadata.ophys_experiment_id, + ophys_session_id=ophys_experiment_metadata._ophys_session_id, experiment_container_id= ophys_experiment_metadata._experiment_container_id, emission_lambda=ophys_experiment_metadata._emission_lambda, @@ -86,6 +97,8 @@ def from_nwb(cls, nwbfile: NWBFile) -> "MesoscopeExperimentMetadata": ophys_experiment_metadata = super().from_nwb(nwbfile=nwbfile) imaging_plane_group = ImagingPlaneGroup.from_nwb(nwbfile=nwbfile) return cls( + ophys_experiment_id=ophys_experiment_metadata.ophys_experiment_id, + ophys_session_id=ophys_experiment_metadata._ophys_session_id, experiment_container_id= ophys_experiment_metadata._experiment_container_id, emission_lambda=ophys_experiment_metadata._emission_lambda, diff --git a/allensdk/brain_observatory/comparison_utils.py b/allensdk/brain_observatory/comparison_utils.py new file mode 100644 index 000000000..4df97759e --- /dev/null +++ b/allensdk/brain_observatory/comparison_utils.py @@ -0,0 +1,60 @@ +import datetime +import math +from typing import Any + +import SimpleITK as sitk +import numpy as np +import pandas as pd +import xarray as xr +from pandas.util.testing import assert_frame_equal + + +def compare_fields(x1: Any, x2: Any, err_msg=""): + """Helper function to compare if two fields (attributes) + are equal to one another. + + Parameters + ---------- + x1 : Any + The first field + x2 : Any + The other field + err_msg : str, optional + The error message to display if two compared fields do not equal + one another, by default "" (an empty string) + """ + if isinstance(x1, pd.DataFrame): + try: + assert_frame_equal(x1, x2, check_like=True) + except Exception: + print(err_msg) + raise + elif isinstance(x1, np.ndarray): + np.testing.assert_array_almost_equal(x1, x2, err_msg=err_msg) + elif isinstance(x1, xr.DataArray): + xr.testing.assert_allclose(x1, x2) + elif isinstance(x1, (list,)): + assert x1 == x2, err_msg + elif isinstance(x1, (sitk.Image,)): + assert x1.GetSize() == x2.GetSize(), err_msg + assert x1 == x2, err_msg + elif isinstance(x1, (datetime.datetime, pd.Timestamp)): + if isinstance(x1, pd.Timestamp): + x1 = x1.to_pydatetime() + if isinstance(x2, pd.Timestamp): + x2 = x2.to_pydatetime() + time_delta = (x1 - x2).total_seconds() + # Timestamp differences should be less than 60 seconds + assert abs(time_delta) < 60 + elif isinstance(x1, (float,)): + if math.isnan(x1) or math.isnan(x2): + both_nan = (math.isnan(x1) and math.isnan(x2)) + assert both_nan, err_msg + else: + assert x1 == x2, err_msg + elif isinstance(x1, (dict,)): + for key in set(x1.keys()).union(set(x2.keys())): + key_err_msg = f"Mismatch when checking key {key}. {err_msg}" + compare_fields(x1[key], x2[key], err_msg=key_err_msg) + else: + assert x1 == x2, err_msg \ No newline at end of file diff --git a/allensdk/brain_observatory/session_api_utils.py b/allensdk/brain_observatory/session_api_utils.py index c46b034b3..db8090b9c 100644 --- a/allensdk/brain_observatory/session_api_utils.py +++ b/allensdk/brain_observatory/session_api_utils.py @@ -1,19 +1,14 @@ import inspect import logging -import math import warnings -import datetime from itertools import zip_longest from typing import Any, Dict, List import numpy as np import pandas as pd -import xarray as xr -import SimpleITK as sitk - -from pandas.util.testing import assert_frame_equal +from allensdk.brain_observatory.comparison_utils import compare_fields from allensdk.core.lazy_property import LazyProperty from allensdk.brain_observatory.behavior.data_objects import DataObject @@ -194,7 +189,7 @@ def sessions_are_equal(A, B, reraise=False) -> bool: x1 = x1.value if isinstance(x2, DataObject): x2 = x2.value - compare_session_fields(x1, x2, err_msg) + compare_fields(x1, x2, err_msg) except NotImplementedError: A_implements_get_field = hasattr( @@ -210,54 +205,3 @@ def sessions_are_equal(A, B, reraise=False) -> bool: return False return True - - -def compare_session_fields(x1: Any, x2: Any, err_msg=""): - """Helper function to compare if two fields (attributes) from a - Session object are equal to one another. - - Parameters - ---------- - x1 : Any - The field from the first session to compare - x2 : Any - The corresponding field from the second session to compare - err_msg : str, optional - The error message to display if two compared fields do not equal - one another, by default "" (an empty string) - """ - if isinstance(x1, pd.DataFrame): - try: - assert_frame_equal(x1, x2, check_like=True) - except Exception: - print(err_msg) - raise - elif isinstance(x1, np.ndarray): - np.testing.assert_array_almost_equal(x1, x2, err_msg=err_msg) - elif isinstance(x1, xr.DataArray): - xr.testing.assert_allclose(x1, x2) - elif isinstance(x1, (list,)): - assert x1 == x2, err_msg - elif isinstance(x1, (sitk.Image,)): - assert x1.GetSize() == x2.GetSize(), err_msg - assert x1 == x2, err_msg - elif isinstance(x1, (datetime.datetime, pd.Timestamp)): - if isinstance(x1, pd.Timestamp): - x1 = x1.to_pydatetime() - if isinstance(x2, pd.Timestamp): - x2 = x2.to_pydatetime() - time_delta = (x1 - x2).total_seconds() - # Timestamp differences should be less than 60 seconds - assert abs(time_delta) < 60 - elif isinstance(x1, (float,)): - if math.isnan(x1) or math.isnan(x2): - both_nan = (math.isnan(x1) and math.isnan(x2)) - assert both_nan, err_msg - else: - assert x1 == x2, err_msg - elif isinstance(x1, (dict,)): - for key in set(x1.keys()).union(set(x2.keys())): - key_err_msg = f"Mismatch when checking key {key}. {err_msg}" - compare_session_fields(x1[key], x2[key], err_msg=key_err_msg) - else: - assert x1 == x2, err_msg diff --git a/allensdk/test/brain_observatory/behavior/conftest.py b/allensdk/test/brain_observatory/behavior/conftest.py index ff30c0c4d..e74227dd5 100644 --- a/allensdk/test/brain_observatory/behavior/conftest.py +++ b/allensdk/test/brain_observatory/behavior/conftest.py @@ -8,6 +8,46 @@ import pytest import pytz +from allensdk.brain_observatory.behavior.data_objects import BehaviorSessionId +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ + BehaviorMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_session_uuid import \ + BehaviorSessionUUID +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.date_of_acquisition import \ + DateOfAcquisition +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.equipment_name import \ + EquipmentName +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.session_type import \ + SessionType +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.stimulus_frame_rate import \ + StimulusFrameRate +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.age import \ + Age +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.driver_line import \ + DriverLine +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.full_genotype import \ + FullGenotype +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.mouse_id import \ + MouseId +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.reporter_line import \ + ReporterLine +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.sex import \ + Sex +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.subject_metadata import \ + SubjectMetadata from allensdk.brain_observatory.behavior.image_api import ImageApi from allensdk.brain_observatory.behavior.session_apis.data_transforms import \ BehaviorOphysDataTransforms @@ -143,22 +183,31 @@ def stimulus_presentations_behavior(stimulus_templates, @pytest.fixture def behavior_only_metadata_fixture(): """Fixture that provides mock behavior only session metadata""" - return { - "behavior_session_id": 4242, - "session_type": 'Unknown', - "date_of_acquisition": pytz.utc.localize(datetime.datetime.now()), - "reporter_line": "Ai93(TITL-GCaMP6f)", - "driver_line": ["Camk2a-tTA", "Slc17a7-IRES2-Cre"], - "cre_line": "Slc17a7-IRES2-Cre", - "mouse_id": 416369, - "full_genotype": "Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;" - "Ai93(TITL-GCaMP6f)/wt", - "behavior_session_uuid": uuid.uuid4(), - "stimulus_frame_rate": 60.0, - "equipment_name": 'my_device', - "sex": 'M', - "age_in_days": 139 - } + subject_meta = SubjectMetadata( + sex=Sex(sex='M'), + age=Age(age=139), + reporter_line=ReporterLine(reporter_line="Ai93(TITL-GCaMP6f)"), + full_genotype=FullGenotype( + full_genotype="Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;" + "Ai93(TITL-GCaMP6f)/wt"), + driver_line=DriverLine( + driver_line=["Camk2a-tTA", "Slc17a7-IRES2-Cre"]), + mouse_id=MouseId(mouse_id=416369) + + ) + behavior_meta = BehaviorMetadata( + subject_metadata=subject_meta, + behavior_session_id=BehaviorSessionId(behavior_session_id=4242), + equipment_name=EquipmentName(equipment_name='my_device'), + stimulus_frame_rate=StimulusFrameRate(stimulus_frame_rate=60.0), + session_type=SessionType(session_type='Unknown'), + date_of_acquisition=DateOfAcquisition( + date_of_acquisition=pytz.utc.localize(datetime.datetime.now()) + ), + behavior_session_uuid=BehaviorSessionUUID( + behavior_session_uuid=uuid.uuid4()) + ) + return behavior_meta @pytest.fixture diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py index 3833e0fcf..72f936f17 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_experiment.py @@ -15,7 +15,8 @@ from allensdk.brain_observatory.behavior.session_apis.data_io import ( BehaviorOphysNwbApi, BehaviorOphysLimsApi) from allensdk.brain_observatory.session_api_utils import ( - sessions_are_equal, compare_session_fields) + sessions_are_equal) +from allensdk.brain_observatory.comparison_utils import compare_fields from allensdk.brain_observatory.stimulus_info import MONITOR_DIMENSIONS @@ -37,7 +38,7 @@ def test_session_from_json(tmpdir_factory, session_data, get_expected, expected = get_expected(session_data) obtained = get_from_session(session) - compare_session_fields(expected, obtained) + compare_fields(expected, obtained) @pytest.mark.requires_bamboo diff --git a/allensdk/test/brain_observatory/behavior/test_write_behavior_nwb.py b/allensdk/test/brain_observatory/behavior/test_write_behavior_nwb.py index d7a2bc2a7..a214a59cd 100644 --- a/allensdk/test/brain_observatory/behavior/test_write_behavior_nwb.py +++ b/allensdk/test/brain_observatory/behavior/test_write_behavior_nwb.py @@ -8,6 +8,9 @@ import pytest import allensdk.brain_observatory.nwb as nwb +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ + BehaviorMetadata from allensdk.brain_observatory.behavior.session_apis.data_io import ( BehaviorNwbApi) from allensdk.brain_observatory.behavior.stimulus_processing import \ @@ -168,28 +171,19 @@ def test_add_rewards(nwbfile, roundtrip, roundtripper, rewards): check_dtype=False) -@pytest.mark.parametrize('roundtrip', [True, False]) -def test_add_behavior_only_metadata(roundtrip, roundtripper, - behavior_only_metadata_fixture): +def test_add_behavior_only_metadata(behavior_only_metadata_fixture): metadata = behavior_only_metadata_fixture nwbfile = pynwb.NWBFile( session_description='asession', identifier='afile', - session_start_time=metadata['date_of_acquisition'] + session_start_time=metadata.date_of_acquisition ) - nwb.add_metadata(nwbfile, metadata, behavior_only=True) - - if roundtrip: - obt = roundtripper(nwbfile, BehaviorNwbApi) - else: - obt = BehaviorNwbApi.from_nwbfile(nwbfile) + metadata.to_nwb(nwbfile=nwbfile) - metadata_obt = obt.get_metadata() + metadata_obt = BehaviorMetadata.from_nwb(nwbfile=nwbfile) - assert len(metadata_obt) == len(metadata) - for key, val in metadata.items(): - assert val == metadata_obt[key] + assert metadata == metadata_obt @pytest.mark.parametrize('roundtrip', [True, False]) From 9adf77b4826fdd5fbfb671f7bc50fd841f76ddfc Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 22 Jun 2021 14:53:48 -0700 Subject: [PATCH 044/234] adds behavior ophys metadata tests --- .../data_objects/base/_data_object_abc.py | 10 +- .../ophys_experiment_metadata.py | 25 ++-- .../brain_observatory/behavior/conftest.py | 71 +++++---- .../test_behavior_metadata.py | 79 ++++++++++ .../test_behavior_ophys_metadata.py | 141 ++++++++++++++++++ 5 files changed, 285 insertions(+), 41 deletions(-) create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata/test_behavior_ophys_metadata.py diff --git a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py index c159e4797..597e3f6a8 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py @@ -28,7 +28,9 @@ def __init__(self, name: str, value: Any, """ self._name = name self._value = value - self._exclude_from_equals = exclude_from_equals + + efe = exclude_from_equals if exclude_from_equals else set() + self._exclude_from_equals = efe @property def name(self) -> str: @@ -53,11 +55,11 @@ def to_dict(self): for p in path: cur = cur[p] cur[name] = {} - path.append(name) - values = [(name, value, path) for name, value in + newpath = path + [name] + values = [(name, value, newpath) for name, value in value._get_properties().items()] if not values: - q.append((name, value._value, path)) + q.append((name, value._value, newpath)) else: for v in values: q.append(v) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py index e052f8caf..756be1b21 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py @@ -1,3 +1,4 @@ +import warnings from typing import Optional from pynwb import NWBFile @@ -113,15 +114,21 @@ def from_json(cls, dict_repr: dict) -> "OphysExperimentMetadata": @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "OphysExperimentMetadata": - ophys_experiment_id = nwbfile.identifier + if 'ophys' not in nwbfile.processing: + raise RuntimeError('Key "ophys" not found in nwb file ' + '(needed to read imaging plane metadata). ' + 'Did you forget to write cell specimen table ' + 'to nwb?') + + ophys_experiment_id = int(nwbfile.identifier) ophys_session_id = OphysSessionId.from_nwb(nwbfile=nwbfile) experiment_container_id = ExperimentContainerId.from_nwb( nwbfile=nwbfile) imaging_plane = ImagingPlane.from_nwb(nwbfile=nwbfile) - emission_lambda = EmissionLambda() + emission_lambda = EmissionLambda.from_nwb(nwbfile=nwbfile) field_of_view_shape = FieldOfViewShape.from_nwb(nwbfile=nwbfile) imaging_depth = ImagingDepth.from_nwb(nwbfile=nwbfile) - return cls( + return OphysExperimentMetadata( ophys_experiment_id=ophys_experiment_id, ophys_session_id=ophys_session_id, experiment_container_id=experiment_container_id, @@ -165,10 +172,8 @@ def ophys_session_id(self) -> int: @property def project_code(self) -> Optional[str]: - return self._project_code.value - - def to_dict(self) -> dict: - """Returns dict representation of all properties in class""" - vars_ = vars(OphysExperimentMetadata) - d = self._get_properties(vars_=vars_) - return {**super().to_dict(), **d} + if self._project_code is None: + pc = self._project_code + else: + pc = self._project_code.value + return pc diff --git a/allensdk/test/brain_observatory/behavior/conftest.py b/allensdk/test/brain_observatory/behavior/conftest.py index e74227dd5..07afec431 100644 --- a/allensdk/test/brain_observatory/behavior/conftest.py +++ b/allensdk/test/brain_observatory/behavior/conftest.py @@ -27,6 +27,30 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.stimulus_frame_rate import \ StimulusFrameRate +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_ophys_metadata import \ + BehaviorOphysMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.emission_lambda import \ + EmissionLambda +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.experiment_container_id import \ + ExperimentContainerId +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.field_of_view_shape import \ + FieldOfViewShape +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.imaging_depth import \ + ImagingDepth +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.imaging_plane import \ + ImagingPlane +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.ophys_experiment_metadata import \ + OphysExperimentMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.ophys_session_id import \ + OphysSessionId from allensdk.brain_observatory.behavior.data_objects.metadata\ .subject_metadata.age import \ Age @@ -245,33 +269,26 @@ def metadata_fixture(): @pytest.fixture -def partial_metadata_fixture(): - """Fixture that passes only metadata that will be saved in - custom pyNWB extension fields""" - return { - "behavior_session_id": 777, - "ophys_session_id": 999, - "ophys_experiment_id": 1234, - "experiment_container_id": 5678, - "stimulus_frame_rate": 60.0, - "imaging_depth": 375, - "session_type": 'Unknown', - "date_of_acquisition": pytz.utc.localize(datetime.datetime.now()), - "reporter_line": "Ai93(TITL-GCaMP6f)", - "driver_line": ["Camk2a-tTA", "Slc17a7-IRES2-Cre"], - "cre_line": "Slc17a7-IRES2-Cre", - "mouse_id": 416369, - "full_genotype": "Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;" - "Ai93(TITL-GCaMP6f)/wt", - "behavior_session_uuid": uuid.uuid4(), - "field_of_view_width": 4, - "field_of_view_height": 4, - "equipment_name": 'my_device', - "sex": 'M', - "age_in_days": 139, - "imaging_plane_group": None, - "imaging_plane_group_count": 0 - } +def behavior_ophys_metadata_fixture( + behavior_only_metadata_fixture) -> BehaviorOphysMetadata: + ophys_meta = OphysExperimentMetadata( + ophys_experiment_id=1234, + ophys_session_id=OphysSessionId(session_id=999), + experiment_container_id=ExperimentContainerId( + experiment_container_id=5678), + imaging_plane=ImagingPlane( + ophys_frame_rate=31.0, + targeted_structure='VISp', + excitation_lambda=1.0 + ), + emission_lambda=EmissionLambda(emission_lambda=1.0), + field_of_view_shape=FieldOfViewShape(width=4, height=4), + imaging_depth=ImagingDepth(imaging_depth=375) + ) + return BehaviorOphysMetadata( + behavior_metadata=behavior_only_metadata_fixture, + ophys_metadata=ophys_meta + ) @pytest.fixture diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py new file mode 100644 index 000000000..9a7d0911f --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py @@ -0,0 +1,79 @@ +import datetime +import uuid + +import pytz + +from allensdk.brain_observatory.behavior.data_objects import BehaviorSessionId +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ + BehaviorMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_session_uuid import \ + BehaviorSessionUUID +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.date_of_acquisition import \ + DateOfAcquisition +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.equipment_name import \ + EquipmentName +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.session_type import \ + SessionType +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.stimulus_frame_rate import \ + StimulusFrameRate +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.age import \ + Age +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.driver_line import \ + DriverLine +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.full_genotype import \ + FullGenotype +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.mouse_id import \ + MouseId +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.reporter_line import \ + ReporterLine +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.sex import \ + Sex +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.subject_metadata import \ + SubjectMetadata + + +class TestBehaviorMetadata: + @classmethod + def setup_class(cls): + cls.meta = cls._get_meta() + + @staticmethod + def _get_meta(): + subject_meta = SubjectMetadata( + sex=Sex(sex='M'), + age=Age(age=139), + reporter_line=ReporterLine(reporter_line="Ai93(TITL-GCaMP6f)"), + full_genotype=FullGenotype( + full_genotype="Slc17a7-IRES2-Cre/wt;Camk2a-tTA/wt;" + "Ai93(TITL-GCaMP6f)/wt"), + driver_line=DriverLine( + driver_line=["Camk2a-tTA", "Slc17a7-IRES2-Cre"]), + mouse_id=MouseId(mouse_id=416369) + + ) + behavior_meta = BehaviorMetadata( + subject_metadata=subject_meta, + behavior_session_id=BehaviorSessionId(behavior_session_id=4242), + equipment_name=EquipmentName(equipment_name='my_device'), + stimulus_frame_rate=StimulusFrameRate(stimulus_frame_rate=60.0), + session_type=SessionType(session_type='Unknown'), + date_of_acquisition=DateOfAcquisition( + date_of_acquisition=pytz.utc.localize(datetime.datetime.now()) + ), + behavior_session_uuid=BehaviorSessionUUID( + behavior_session_uuid=uuid.uuid4()) + ) + return behavior_meta \ No newline at end of file diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata/test_behavior_ophys_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata/test_behavior_ophys_metadata.py new file mode 100644 index 000000000..ed57991b9 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata/test_behavior_ophys_metadata.py @@ -0,0 +1,141 @@ +import pandas as pd +import pynwb +import pytest + +from allensdk.brain_observatory.behavior.data_objects.cell_specimen_table \ + import \ + CellSpecimenTable +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.session_type import \ + SessionType +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_ophys_metadata import \ + BehaviorOphysMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.emission_lambda import \ + EmissionLambda +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.experiment_container_id import \ + ExperimentContainerId +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.field_of_view_shape import \ + FieldOfViewShape +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.imaging_depth import \ + ImagingDepth +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.imaging_plane import \ + ImagingPlane +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.mesoscope_experiment_metadata\ + .imaging_plane_group import \ + ImagingPlaneGroup +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.mesoscope_experiment_metadata\ + .mesoscope_experiment_metadata import \ + MesoscopeExperimentMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.ophys_experiment_metadata import \ + OphysExperimentMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.ophys_session_id import \ + OphysSessionId +from allensdk.test.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.test_behavior_metadata import \ + TestBehaviorMetadata + + +class TestBehaviorOphysMetadata: + def setup_method(self, method): + self.meta = self._get_meta() + self.nwbfile = pynwb.NWBFile( + session_description='asession', + identifier=str(self.meta.ophys_metadata.ophys_experiment_id), + session_start_time=self.meta.behavior_metadata.date_of_acquisition + ) + + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_write_nwb_read_no_cell_specimen_table( + self, roundtrip, data_object_roundtrip_fixture): + self.meta.to_nwb(nwbfile=self.nwbfile) + + with pytest.raises(RuntimeError): + if roundtrip: + data_object_roundtrip_fixture( + nwbfile=self.nwbfile, + data_object_cls=BehaviorOphysMetadata) + else: + self.meta.from_nwb(nwbfile=self.nwbfile) + + @pytest.mark.parametrize('meso', [True, False]) + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_read_write_nwb(self, roundtrip, cell_specimen_table, + data_object_roundtrip_fixture, meso): + if meso: + self.meta = self._get_mesoscope_meta() + + self.meta.to_nwb(nwbfile=self.nwbfile) + + cell_specimen_table = pd.DataFrame(cell_specimen_table) + cell_specimen_table = CellSpecimenTable( + cell_specimen_table=cell_specimen_table) + cell_specimen_table.to_nwb(nwbfile=self.nwbfile, meta=self.meta) + + if roundtrip: + obt = data_object_roundtrip_fixture( + nwbfile=self.nwbfile, + data_object_cls=BehaviorOphysMetadata) + else: + obt = self.meta.from_nwb(nwbfile=self.nwbfile) + + assert obt == self.meta + + @staticmethod + def _get_meta(): + ophys_meta = OphysExperimentMetadata( + ophys_experiment_id=1234, + ophys_session_id=OphysSessionId(session_id=999), + experiment_container_id=ExperimentContainerId( + experiment_container_id=5678), + imaging_plane=ImagingPlane( + ophys_frame_rate=31.0, + targeted_structure='VISp', + excitation_lambda=1.0 + ), + emission_lambda=EmissionLambda(emission_lambda=1.0), + field_of_view_shape=FieldOfViewShape(width=4, height=4), + imaging_depth=ImagingDepth(imaging_depth=375) + ) + + behavior_metadata = TestBehaviorMetadata() + behavior_metadata.setup_class() + behavior_metadata = behavior_metadata.meta + return BehaviorOphysMetadata( + behavior_metadata=behavior_metadata, + ophys_metadata=ophys_meta + ) + + def _get_mesoscope_meta(self): + bo_meta = self.meta + bo_meta.behavior_metadata._session_type = \ + SessionType(session_type='MESO.1') + ophys_experiment_metadata = bo_meta.ophys_metadata + + imaging_plane_group = ImagingPlaneGroup(plane_group_count=5, + plane_group=0) + meso_meta = MesoscopeExperimentMetadata( + ophys_experiment_id=ophys_experiment_metadata.ophys_experiment_id, + ophys_session_id=ophys_experiment_metadata._ophys_session_id, + experiment_container_id= + ophys_experiment_metadata._experiment_container_id, + emission_lambda=ophys_experiment_metadata._emission_lambda, + imaging_plane=ophys_experiment_metadata._imaging_plane, + field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, + imaging_depth=ophys_experiment_metadata._imaging_depth, + project_code=ophys_experiment_metadata._project_code, + imaging_plane_group=imaging_plane_group + ) + return BehaviorOphysMetadata( + behavior_metadata=bo_meta.behavior_metadata, + ophys_metadata=meso_meta + ) From 49670896ed9a116ccbc4bc3139b5a45df909021c Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 23 Jun 2021 05:59:49 -0700 Subject: [PATCH 045/234] rename old test beh meta to avoid name conflict; move old tests to new module; update running speed, stim ts tests due to api change --- .../test_behavior_metadata.py | 184 ++++++++++++++++-- .../running_speed/test_running_acquisition.py | 9 +- .../running_speed/test_running_speed.py | 9 +- .../test_stimulus_timestamps.py | 47 ++--- ...ta.py => test_behavior_metadata_legacy.py} | 155 --------------- .../behavior/test_write_nwb_behavior_ophys.py | 39 ---- 6 files changed, 202 insertions(+), 241 deletions(-) rename allensdk/test/brain_observatory/behavior/{test_behavior_metadata.py => test_behavior_metadata_legacy.py} (73%) diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py index 9a7d0911f..5f798747d 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py @@ -1,46 +1,49 @@ import datetime +import pickle import uuid +import pytest import pytz +from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import BehaviorSessionId -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .behavior_metadata.behavior_metadata import \ BehaviorMetadata -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .behavior_metadata.behavior_session_uuid import \ BehaviorSessionUUID -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .behavior_metadata.date_of_acquisition import \ DateOfAcquisition -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .behavior_metadata.equipment_name import \ EquipmentName -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .behavior_metadata.session_type import \ SessionType -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .behavior_metadata.stimulus_frame_rate import \ StimulusFrameRate -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.age import \ Age -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.driver_line import \ DriverLine -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.full_genotype import \ FullGenotype -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.mouse_id import \ MouseId -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.reporter_line import \ ReporterLine -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.sex import \ Sex -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.subject_metadata import \ SubjectMetadata @@ -76,4 +79,157 @@ def _get_meta(): behavior_session_uuid=BehaviorSessionUUID( behavior_session_uuid=uuid.uuid4()) ) - return behavior_meta \ No newline at end of file + return behavior_meta + + def test_cre_line(self): + """Tests that cre_line properly parsed from driver_line""" + fg = FullGenotype( + full_genotype='Sst-IRES-Cre/wt;Ai148(TIT2L-GC6f-ICL-tTA2)/wt') + assert fg.parse_cre_line() == 'Sst-IRES-Cre' + + def test_cre_line_bad_full_genotype(self): + """Test that cre_line is None and no error raised""" + fg = FullGenotype(full_genotype='foo') + + with pytest.warns(UserWarning) as record: + cre_line = fg.parse_cre_line(warn=True) + assert cre_line is None + assert str(record[0].message) == 'Unable to parse cre_line from ' \ + 'full_genotype' + + def test_reporter_line(self): + """Test that reporter line properly parsed from list""" + reporter_line = ReporterLine._parse(reporter_line=['foo']) + assert reporter_line == 'foo' + + def test_reporter_line_str(self): + """Test that reporter line returns itself if str""" + reporter_line = ReporterLine._parse(reporter_line='foo') + assert reporter_line == 'foo' + + @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( + (('foo', 'bar'), 'More than 1 reporter line. ' + 'Returning the first one', 'foo'), + (None, 'Error parsing reporter line. It is null.', None), + ([], 'Error parsing reporter line. The array is empty', None) + ) + ) + def test_reporter_edge_cases(self, input_reporter_line, warning_msg, + expected): + """Test reporter line edge cases""" + with pytest.warns(UserWarning) as record: + reporter_line = ReporterLine._parse( + reporter_line=input_reporter_line, + warn=True) + assert reporter_line == expected + assert str(record[0].message) == warning_msg + + def test_age_in_days(self): + """Test that age_in_days properly parsed from age""" + age = Age._age_code_to_days(age='P123') + assert age == 123 + + @pytest.mark.parametrize("input_age, warning_msg, expected", ( + ('unkown', 'Could not parse numeric age from age code ' + '(age code does not start with "P")', None), + ('P', 'Could not parse numeric age from age code ' + '(no numeric values found in age code)', None) + ) + ) + def test_age_in_days_edge_cases(self, monkeypatch, input_age, warning_msg, + expected): + """Test age in days edge cases""" + with pytest.warns(UserWarning) as record: + age_in_days = Age._age_code_to_days(age=input_age, warn=True) + + assert age_in_days is None + assert str(record[0].message) == warning_msg + + @pytest.mark.parametrize("test_params, expected_warn_msg", [ + # Vanilla test case + ({ + "extractor_expt_date": datetime.datetime.strptime( + "2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": datetime.datetime.strptime("2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "behavior_session_id": 1 + }, None), + + # pkl expt date stored in unix format + ({ + "extractor_expt_date": datetime.datetime.strptime( + "2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": 1615716855.0, + "behavior_session_id": 2 + }, None), + + # Extractor and pkl dates differ significantly + ({ + "extractor_expt_date": datetime.datetime.strptime( + "2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": datetime.datetime.strptime("2021-03-14 20:14:15", + "%Y-%m-%d %H:%M:%S"), + "behavior_session_id": 3 + }, + "The `date_of_acquisition` field in LIMS *"), + + # pkl file contains an unparseable datetime + ({ + "extractor_expt_date": datetime.datetime.strptime( + "2021-03-14 03:14:15", + "%Y-%m-%d %H:%M:%S"), + "pkl_expt_date": None, + "behavior_session_id": 4 + }, + "Could not parse the acquisition datetime *"), + ]) + def test_get_date_of_acquisition(self, tmp_path, test_params, + expected_warn_msg): + mock_session_id = test_params["behavior_session_id"] + + pkl_save_path = tmp_path / f"mock_pkl_{mock_session_id}.pkl" + with open(pkl_save_path, 'wb') as handle: + pickle.dump({"start_time": test_params['pkl_expt_date']}, handle) + + tz = pytz.timezone("America/Los_Angeles") + extractor_expt_date = tz.localize( + test_params['extractor_expt_date']).astimezone(pytz.utc) + + stimulus_file = StimulusFile(filepath=pkl_save_path) + obt_date = DateOfAcquisition( + date_of_acquisition=extractor_expt_date) + + if expected_warn_msg: + with pytest.warns(Warning, match=expected_warn_msg): + obt_date.validate( + stimulus_file=stimulus_file, + behavior_session_id=test_params['behavior_session_id']) + + assert obt_date.value == extractor_expt_date + + def test_indicator(self): + """Test that indicator is parsed from full_genotype""" + reporter_line = ReporterLine( + reporter_line='Ai148(TIT2L-GC6f-ICL-tTA2)') + assert reporter_line.parse_indicator() == 'GCaMP6f' + + @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( + (None, + 'Could not parse indicator from reporter because there is no ' + 'reporter', None), + ('foo', 'Could not parse indicator from reporter because none' + 'of the expected substrings were found in the reporter', + None) + ) + ) + def test_indicator_edge_cases(self, input_reporter_line, warning_msg, + expected): + """Test indicator parsing edge cases""" + with pytest.warns(UserWarning) as record: + reporter_line = ReporterLine(reporter_line=input_reporter_line) + indicator = reporter_line.parse_indicator(warn=True) + assert indicator is expected + assert str(record[0].message) == warning_msg diff --git a/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_acquisition.py b/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_acquisition.py index 94373114c..fc93f1b9f 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_acquisition.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_acquisition.py @@ -260,12 +260,11 @@ def test_running_acquisition_from_lims( ) assert obt._stimulus_file == mock_stimulus_file_instance - mock_stimulus_timestamps.from_lims.assert_called_once_with( - mock_db_conn, behavior_session_id, ophys_experiment_id - ) - mock_stimulus_timestamps_instance = mock_stimulus_timestamps.from_lims( - mock_db_conn, behavior_session_id, ophys_experiment_id + mock_stimulus_timestamps.from_stimulus_file.assert_called_once_with( + mock_stimulus_file_instance ) + mock_stimulus_timestamps_instance = mock_stimulus_timestamps.\ + from_stimulus_file(stimulus_file=mock_stimulus_file) assert obt._stimulus_timestamps == mock_stimulus_timestamps_instance mock_get_running_df.assert_called_once_with( diff --git a/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_speed.py b/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_speed.py index f207cd542..8bfc27049 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_speed.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/running_speed/test_running_speed.py @@ -303,12 +303,11 @@ def test_running_speed_from_lims( ) assert obt._stimulus_file == mock_stimulus_file_instance - mock_stimulus_timestamps.from_lims.assert_called_once_with( - mock_db_conn, behavior_session_id, ophys_experiment_id - ) - mock_stimulus_timestamps_instance = mock_stimulus_timestamps.from_lims( - mock_db_conn, behavior_session_id, ophys_experiment_id + mock_stimulus_timestamps.from_stimulus_file.assert_called_once_with( + mock_stimulus_file_instance ) + mock_stimulus_timestamps_instance = mock_stimulus_timestamps.\ + from_stimulus_file(stimulus_file=mock_stimulus_file) assert obt._stimulus_timestamps == mock_stimulus_timestamps_instance mock_get_running_speed_df.assert_called_once_with( diff --git a/allensdk/test/brain_observatory/behavior/data_objects/stimulus_timestamps/test_stimulus_timestamps.py b/allensdk/test/brain_observatory/behavior/data_objects/stimulus_timestamps/test_stimulus_timestamps.py index f53e381f1..0db164161 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/stimulus_timestamps/test_stimulus_timestamps.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/stimulus_timestamps/test_stimulus_timestamps.py @@ -74,20 +74,22 @@ def test_stimulus_timestamps_from_json( ".get_ophys_stimulus_timestamps", mock_get_ophys_stimulus_timestamps ) - obt = StimulusTimestamps.from_json(dict_repr) + mock_stimulus_file_instance = mock_stimulus_file.from_json(dict_repr) + ts_from_stim = StimulusTimestamps.from_stimulus_file( + stimulus_file=mock_stimulus_file_instance) - mock_stimulus_file.from_json.assert_called_with(dict_repr) - mock_stimulus_file_instance = mock_stimulus_file.from_json(dict_repr) - assert obt._stimulus_file == mock_stimulus_file_instance + if has_pkl and has_sync: + mock_sync_file_instance = mock_sync_file.from_json(dict_repr) + ts_from_sync = StimulusTimestamps.from_sync_file( + sync_file=mock_sync_file_instance) if has_pkl and has_sync: - mock_sync_file.from_json.assert_called_with(dict_repr) - mock_sync_file_instance = mock_sync_file.from_json(dict_repr) mock_get_ophys_stimulus_timestamps.assert_called_once_with( sync_path=mock_sync_file_instance.filepath ) - assert obt._sync_file == mock_sync_file_instance + assert ts_from_sync._sync_file == mock_sync_file_instance else: + assert ts_from_stim._stimulus_file == mock_stimulus_file_instance mock_get_behavior_stimulus_timestamps.assert_called_once_with( stimulus_pkl=mock_stimulus_file_instance.data ) @@ -215,30 +217,29 @@ def test_stimulus_timestamps_from_lims( ".get_ophys_stimulus_timestamps", mock_get_ophys_stimulus_timestamps ) - obt = StimulusTimestamps.from_lims( - mock_db_conn, behavior_session_id, ophys_experiment_id + mock_stimulus_file_instance = mock_stimulus_file.from_lims( + mock_db_conn, behavior_session_id ) + ts_from_stim = StimulusTimestamps.from_stimulus_file( + stimulus_file=mock_stimulus_file_instance) + assert ts_from_stim._stimulus_file == mock_stimulus_file_instance - mock_stimulus_file.from_lims.assert_called_with( - mock_db_conn, behavior_session_id - ) - mock_stimulus_file_instance = mock_stimulus_file.from_lims( - mock_db_conn, behavior_session_id - ) - assert obt._stimulus_file == mock_stimulus_file_instance + if behavior_session_id is not None and ophys_experiment_id is not None: + mock_sync_file_instance = mock_sync_file.from_lims( + mock_db_conn, ophys_experiment_id + ) + ts_from_sync = StimulusTimestamps.from_sync_file( + sync_file=mock_sync_file_instance) if behavior_session_id is not None and ophys_experiment_id is not None: - mock_sync_file.from_lims.assert_called_with( - mock_db_conn, ophys_experiment_id - ) - mock_sync_file_instance = mock_sync_file.from_lims( - mock_db_conn, ophys_experiment_id - ) mock_get_ophys_stimulus_timestamps.assert_called_once_with( sync_path=mock_sync_file_instance.filepath ) - assert obt._sync_file == mock_sync_file_instance + assert ts_from_sync._sync_file == mock_sync_file_instance else: + mock_stimulus_file.from_lims.assert_called_with( + mock_db_conn, behavior_session_id + ) mock_get_behavior_stimulus_timestamps.assert_called_once_with( stimulus_pkl=mock_stimulus_file_instance.data ) diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py b/allensdk/test/brain_observatory/behavior/test_behavior_metadata_legacy.py similarity index 73% rename from allensdk/test/brain_observatory/behavior/test_behavior_metadata.py rename to allensdk/test/brain_observatory/behavior/test_behavior_metadata_legacy.py index 3f2514a29..44e4aee0c 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_metadata_legacy.py @@ -336,158 +336,3 @@ def test_get_expt_description_with_valid_session_type(session_type, def test_get_expt_description_raises_with_invalid_session_type(session_type): with pytest.raises(RuntimeError, match="session type should match.*"): get_expt_description(session_type) - - -def test_cre_line(): - """Tests that cre_line properly parsed from driver_line""" - fg = FullGenotype( - full_genotype='Sst-IRES-Cre/wt;Ai148(TIT2L-GC6f-ICL-tTA2)/wt') - assert fg.parse_cre_line() == 'Sst-IRES-Cre' - - -def test_cre_line_bad_full_genotype(): - """Test that cre_line is None and no error raised""" - fg = FullGenotype(full_genotype='foo') - - with pytest.warns(UserWarning) as record: - cre_line = fg.parse_cre_line(warn=True) - assert cre_line is None - assert str(record[0].message) == 'Unable to parse cre_line from ' \ - 'full_genotype' - - -def test_reporter_line(): - """Test that reporter line properly parsed from list""" - reporter_line = ReporterLine._parse(reporter_line=['foo']) - assert reporter_line == 'foo' - - -def test_reporter_line_str(): - """Test that reporter line returns itself if str""" - reporter_line = ReporterLine._parse(reporter_line='foo') - assert reporter_line == 'foo' - - -@pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( - (('foo', 'bar'), 'More than 1 reporter line. ' - 'Returning the first one', 'foo'), - (None, 'Error parsing reporter line. It is null.', None), - ([], 'Error parsing reporter line. The array is empty', None) -) - ) -def test_reporter_edge_cases(input_reporter_line, warning_msg, - expected): - """Test reporter line edge cases""" - with pytest.warns(UserWarning) as record: - reporter_line = ReporterLine._parse(reporter_line=input_reporter_line, - warn=True) - assert reporter_line == expected - assert str(record[0].message) == warning_msg - - -def test_age_in_days(): - """Test that age_in_days properly parsed from age""" - age = Age._age_code_to_days(age='P123') - assert age == 123 - - -@pytest.mark.parametrize("input_age, warning_msg, expected", ( - ('unkown', 'Could not parse numeric age from age code ' - '(age code does not start with "P")', None), - ('P', 'Could not parse numeric age from age code ' - '(no numeric values found in age code)', None) -) - ) -def test_age_in_days_edge_cases(monkeypatch, input_age, warning_msg, - expected): - """Test age in days edge cases""" - with pytest.warns(UserWarning) as record: - age_in_days = Age._age_code_to_days(age=input_age, warn=True) - - assert age_in_days is None - assert str(record[0].message) == warning_msg - - -@pytest.mark.parametrize("test_params, expected_warn_msg", [ - # Vanilla test case - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "behavior_session_id": 1 - }, None), - - # pkl expt date stored in unix format - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": 1615716855.0, - "behavior_session_id": 2 - }, None), - - # Extractor and pkl dates differ significantly - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": datetime.strptime("2021-03-14 20:14:15", - "%Y-%m-%d %H:%M:%S"), - "behavior_session_id": 3 - }, - "The `date_of_acquisition` field in LIMS *"), - - # pkl file contains an unparseable datetime - ({ - "extractor_expt_date": datetime.strptime("2021-03-14 03:14:15", - "%Y-%m-%d %H:%M:%S"), - "pkl_expt_date": None, - "behavior_session_id": 4 - }, - "Could not parse the acquisition datetime *"), -]) -def test_get_date_of_acquisition(tmp_path, test_params, - expected_warn_msg): - mock_session_id = test_params["behavior_session_id"] - - pkl_save_path = tmp_path / f"mock_pkl_{mock_session_id}.pkl" - with open(pkl_save_path, 'wb') as handle: - pickle.dump({"start_time": test_params['pkl_expt_date']}, handle) - - tz = pytz.timezone("America/Los_Angeles") - extractor_expt_date = tz.localize( - test_params['extractor_expt_date']).astimezone(pytz.utc) - - stimulus_file = StimulusFile(filepath=pkl_save_path) - obt_date = DateOfAcquisition( - date_of_acquisition=extractor_expt_date) - - if expected_warn_msg: - with pytest.warns(Warning, match=expected_warn_msg): - obt_date.validate( - stimulus_file=stimulus_file, - behavior_session_id=test_params['behavior_session_id']) - - assert obt_date.value == extractor_expt_date - - -def test_indicator(): - """Test that indicator is parsed from full_genotype""" - reporter_line = ReporterLine(reporter_line='Ai148(TIT2L-GC6f-ICL-tTA2)') - assert reporter_line.parse_indicator() == 'GCaMP6f' - - -@pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( - (None, 'Could not parse indicator from reporter because there is no ' - 'reporter', None), - ('foo', 'Could not parse indicator from reporter because none' - 'of the expected substrings were found in the reporter', None) -) - ) -def test_indicator_edge_cases(input_reporter_line, warning_msg, - expected): - """Test indicator parsing edge cases""" - with pytest.warns(UserWarning) as record: - reporter_line = ReporterLine(reporter_line=input_reporter_line) - indicator = reporter_line.parse_indicator(warn=True) - assert indicator is expected - assert str(record[0].message) == warning_msg diff --git a/allensdk/test/brain_observatory/behavior/test_write_nwb_behavior_ophys.py b/allensdk/test/brain_observatory/behavior/test_write_nwb_behavior_ophys.py index 7d20621b7..233fead81 100644 --- a/allensdk/test/brain_observatory/behavior/test_write_nwb_behavior_ophys.py +++ b/allensdk/test/brain_observatory/behavior/test_write_nwb_behavior_ophys.py @@ -138,45 +138,6 @@ def test_segmentation_mask_image(nwbfile, roundtrip, roundtripper, image_api.deserialize(obt.get_segmentation_mask_image()) -@pytest.mark.parametrize('test_partial_metadata', [True, False]) -@pytest.mark.parametrize('roundtrip', [True, False]) -def test_add_partial_metadata(test_partial_metadata, roundtrip, roundtripper, - cell_specimen_table, - metadata_fixture, partial_metadata_fixture): - if test_partial_metadata: - meta = partial_metadata_fixture - else: - meta = metadata_fixture - - nwbfile = pynwb.NWBFile( - session_description='asession', - identifier='afile', - session_start_time=meta['date_of_acquisition'] - ) - nwb.add_metadata(nwbfile, meta, behavior_only=False) - if not test_partial_metadata: - nwb.add_cell_specimen_table(nwbfile, cell_specimen_table, meta) - - if roundtrip: - obt = roundtripper(nwbfile, BehaviorOphysNwbApi) - else: - obt = BehaviorOphysNwbApi.from_nwbfile(nwbfile) - - if not test_partial_metadata: - metadata_obt = obt.get_metadata() - else: - with warnings.catch_warnings(record=True) as record: - metadata_obt = obt.get_metadata() - exp_warn_msg = "Could not locate 'ophys' module in NWB" - print(record) - - assert record[0].message.args[0].startswith(exp_warn_msg) - - assert len(metadata_obt) == len(meta) - for key, val in meta.items(): - assert val == metadata_obt[key] - - @pytest.mark.parametrize('roundtrip', [True, False]) def test_add_task_parameters(nwbfile, roundtrip, roundtripper, task_parameters): From 396441882ff82285eb58da0c4470c8afbd326061 Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 23 Jun 2021 06:22:37 -0700 Subject: [PATCH 046/234] undoes api change --- .../stimulus_timestamps.py | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py index b1d3108e1..caa7e6f11 100644 --- a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py +++ b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py @@ -8,6 +8,12 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.json_readable_interface import \ + JsonReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .readable_interfaces.lims_readable_interface import \ + LimsReadableInterface from allensdk.brain_observatory.behavior.data_objects.base\ .readable_interfaces.nwb_readable_interface import \ NwbReadableInterface @@ -31,6 +37,7 @@ from allensdk.brain_observatory.behavior.data_objects.stimulus_timestamps.timestamps_processing import ( # noqa: E501 get_behavior_stimulus_timestamps, get_ophys_stimulus_timestamps ) +from allensdk.internal.api import PostgresQueryMixin def from_json_cache_key(cls, dict_repr: dict): @@ -45,7 +52,8 @@ def from_lims_cache_key( class StimulusTimestamps(DataObject, StimulusFileReadableInterface, - SyncFileReadableInterface, NwbReadableInterface, + SyncFileReadableInterface, JsonReadableInterface, + NwbReadableInterface, LimsReadableInterface, NwbWritableInterface, JsonWritableInterface): """A DataObject which contains properties and methods to load, process, and represent visual behavior stimulus timestamp data. @@ -89,6 +97,30 @@ def from_sync_file(cls, sync_file: SyncFile) -> "StimulusTimestamps": sync_file=sync_file ) + @classmethod + def from_json(cls, dict_repr: dict) -> "StimulusTimestamps": + if 'sync_file' in dict_repr: + sync_file = SyncFile.from_json(dict_repr=dict_repr) + return cls.from_sync_file(sync_file=sync_file) + else: + stim_file = StimulusFile.from_json(dict_repr=dict_repr) + return cls.from_stimulus_file(stimulus_file=stim_file) + + def from_lims( + cls, + db: PostgresQueryMixin, + behavior_session_id: int, + ophys_experiment_id: Optional[int] = None + ) -> "StimulusTimestamps": + stimulus_file = StimulusFile.from_lims(db, behavior_session_id) + + if ophys_experiment_id: + sync_file = SyncFile.from_lims( + db=db, ophys_experiment_id=ophys_experiment_id) + return cls.from_sync_file(sync_file=sync_file) + else: + return cls.from_stimulus_file(stimulus_file=stimulus_file) + def to_json(self) -> dict: if self._stimulus_file is None: raise RuntimeError( From 7739777c6ddcc313e3402ae6fe45172711234c3d Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 23 Jun 2021 06:33:29 -0700 Subject: [PATCH 047/234] Updates behavior_project_cache --- .../tables/sessions_table.py | 17 +++++++++++------ .../metadata/subject_metadata/reporter_line.py | 8 ++++---- .../test-reports/test.xml | 1 - .../behavior_metadata/test_behavior_metadata.py | 6 +++--- 4 files changed, 18 insertions(+), 14 deletions(-) delete mode 100644 allensdk/test/brain_observatory/behavior/behavior_project_cache/test-reports/test.xml diff --git a/allensdk/brain_observatory/behavior/behavior_project_cache/tables/sessions_table.py b/allensdk/brain_observatory/behavior/behavior_project_cache/tables/sessions_table.py index ed4d8b026..22d1c026c 100644 --- a/allensdk/brain_observatory/behavior/behavior_project_cache/tables/sessions_table.py +++ b/allensdk/brain_observatory/behavior/behavior_project_cache/tables/sessions_table.py @@ -13,11 +13,16 @@ from allensdk.brain_observatory.behavior.behavior_project_cache.tables \ .project_table import \ ProjectTable -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.behavior_metadata import \ - BehaviorMetadata from allensdk.brain_observatory.behavior.behavior_project_cache.project_apis.data_io import BehaviorProjectLimsApi # noqa: E501 +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.full_genotype import \ + FullGenotype + +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.reporter_line import \ + ReporterLine + class SessionsTable(ProjectTable): """Class for storing and manipulating project-level data @@ -46,11 +51,11 @@ def __init__( def postprocess_additional(self): self._df['reporter_line'] = self._df['reporter_line'].apply( - BehaviorMetadata.parse_reporter_line) + ReporterLine.parse) self._df['cre_line'] = self._df['full_genotype'].apply( - BehaviorMetadata.parse_cre_line) + lambda x: FullGenotype(x).parse_cre_line()) self._df['indicator'] = self._df['reporter_line'].apply( - BehaviorMetadata.parse_indicator) + lambda x: ReporterLine(x).parse_indicator()) self.__add_session_number() diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py index 7ec7d0877..49f5a36ec 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py @@ -29,7 +29,7 @@ def __init__(self, reporter_line: Optional[str]): @classmethod def from_json(cls, dict_repr: dict) -> "ReporterLine": reporter_line = dict_repr['reporter_line'] - reporter_line = cls._parse(reporter_line=reporter_line, warn=True) + reporter_line = cls.parse(reporter_line=reporter_line, warn=True) return cls(reporter_line=reporter_line) def to_json(self) -> dict: @@ -53,7 +53,7 @@ def from_lims(cls, behavior_session_id: int, raise OneOrMoreResultExpectedError( f"Expected one or more, but received: '{result}' " f"from query:\n'{query}'") - reporter_line = cls._parse(reporter_line=result, warn=True) + reporter_line = cls.parse(reporter_line=result, warn=True) return cls(reporter_line=reporter_line) @classmethod @@ -61,8 +61,8 @@ def from_nwb(cls, nwbfile: NWBFile) -> "ReporterLine": return cls(reporter_line=nwbfile.subject.reporter_line) @staticmethod - def _parse(reporter_line: Union[Optional[List[str]], str], - warn=False) -> Optional[str]: + def parse(reporter_line: Union[Optional[List[str]], str], + warn=False) -> Optional[str]: """There can be multiple reporter lines, so it is returned from LIMS as a list. But there shouldn't be more than 1 for behavior. This tries to convert to str diff --git a/allensdk/test/brain_observatory/behavior/behavior_project_cache/test-reports/test.xml b/allensdk/test/brain_observatory/behavior/behavior_project_cache/test-reports/test.xml deleted file mode 100644 index 33eb7abd3..000000000 --- a/allensdk/test/brain_observatory/behavior/behavior_project_cache/test-reports/test.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py index 5f798747d..ec2a43635 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py @@ -99,12 +99,12 @@ def test_cre_line_bad_full_genotype(self): def test_reporter_line(self): """Test that reporter line properly parsed from list""" - reporter_line = ReporterLine._parse(reporter_line=['foo']) + reporter_line = ReporterLine.parse(reporter_line=['foo']) assert reporter_line == 'foo' def test_reporter_line_str(self): """Test that reporter line returns itself if str""" - reporter_line = ReporterLine._parse(reporter_line='foo') + reporter_line = ReporterLine.parse(reporter_line='foo') assert reporter_line == 'foo' @pytest.mark.parametrize("input_reporter_line, warning_msg, expected", ( @@ -118,7 +118,7 @@ def test_reporter_edge_cases(self, input_reporter_line, warning_msg, expected): """Test reporter line edge cases""" with pytest.warns(UserWarning) as record: - reporter_line = ReporterLine._parse( + reporter_line = ReporterLine.parse( reporter_line=input_reporter_line, warn=True) assert reporter_line == expected From e45cc87f19275d04ddbadc4ed0609ad80640c931 Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 23 Jun 2021 06:53:34 -0700 Subject: [PATCH 048/234] updates monitor delay test --- .../test_behavior_ophys_data_xforms.py | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py index 798c20bb0..86f2b7813 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py @@ -6,8 +6,14 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_metadata import \ BehaviorMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.equipment_name import \ + EquipmentName from allensdk.brain_observatory.behavior.session_apis.data_transforms import BehaviorOphysDataTransforms # noqa: E501 from allensdk.internal.brain_observatory.time_sync import OphysTimeAligner +from allensdk.test.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.test_behavior_metadata import \ + TestBehaviorMetadata @pytest.mark.parametrize("roi_ids,expected", [ @@ -437,25 +443,6 @@ def dummy_delay(self): 'CAM2P.5': 0.021192, 'MESO.1': 0.03613} - def dummy_get_metadata(self): - def dummy_metadata_init(self, extractor): - self._extractor = extractor - - ctx.setattr(BehaviorMetadata, - '__init__', - dummy_metadata_init) - - class DummyExtractor: - def get_sync_file(self): - return '' - - def get_equipment_name(self): - return equipment_name - - metadata = BehaviorMetadata( - extractor=DummyExtractor()) - return metadata - for equipment_name in delay_lookup.keys(): expected_delay = delay_lookup[equipment_name] @@ -464,6 +451,14 @@ def get_equipment_name(self): '__init__', xform_init) + def dummy_get_metadata(self): + test_beh_meta = TestBehaviorMetadata() + test_beh_meta.setup_class() + metadata = test_beh_meta.meta + metadata._equipment_name = EquipmentName( + equipment_name=equipment_name) + return metadata + ctx.setattr(BehaviorOphysDataTransforms, 'get_metadata', dummy_get_metadata) From d4efed075b899815afe0cc9d618927ebbaeff344 Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 23 Jun 2021 14:52:43 -0700 Subject: [PATCH 049/234] Improvements to to_dict --- .../data_objects/base/_data_object_abc.py | 82 +++++++++++++++---- 1 file changed, 64 insertions(+), 18 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py index 597e3f6a8..9f2df514e 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py @@ -44,25 +44,78 @@ def value(self) -> Any: def _get_vars(cls): return vars(cls) - def to_dict(self): + def to_dict(self) -> dict: + """ + Serialize DataObject to dict + :return + A nested dict serializing the DataObject + + notes + If a DataObject contains properties, these properties will either: + 1) be serialized to nested dict with "name" attribute of + DataObject if the property is itself a DataObject + 2) Value for property will be added with name of property + :examples + >>> class Simple(DataObject): + ... def __init__(self): + ... super().__init__(name='simple', value=1) + >>> s = Simple() + >>> s.to_dict() == {'simple': 1} + + >>> class B(DataObject): + ... def __init__(self): + ... super().__init__(name='b', value='!') + + >>> class A(DataObject): + ... def __init__(self, b: B): + ... super().__init__(name='simple', value=self) + ... self._b = b + ... @property + ... def prop1(self): + ... return self._b + ... @property + ... def prop2(self): + ... return '@' + >>> a = A() + >>> a.to_dict() == {'a': {'b': '!'}, 'prop2': '@'} + """ res = {} - q = deque([(name, value, []) for name, value in - self._get_properties().items()]) + q = deque([(self._name, self, [])]) + while q: name, value, path = q.popleft() if isinstance(value, DataObject): + # The path stores the nested key structure + # Here, build onto the nested key structure + newpath = path + [name] + + def _get_keys_and_values(value: DataObject): + properties = [] + for name, value in value._get_properties().items(): + if isinstance(value, DataObject): + # The key will be the DataObject "name" field + name = value._name + else: + # The key will be the property name + pass + properties.append((name, value, newpath)) + return properties + properties = _get_keys_and_values(value=value) + + # Find the nested dict cur = res for p in path: cur = cur[p] - cur[name] = {} - newpath = path + [name] - values = [(name, value, newpath) for name, value in - value._get_properties().items()] - if not values: - q.append((name, value._value, newpath)) + + if properties: + # it's nested + cur[value._name] = {} + for p in properties: + q.append(p) else: - for v in values: - q.append(v) + # it's flat + cur[name] = value._value + else: cur = res for p in path: @@ -85,13 +138,6 @@ def __eq__(self, other: "DataObject"): d_self = self.to_dict() d_other = other.to_dict() - # if not isinstance(self._value, DataObject): - # properties_self['value'] = self._value - # properties_other['value'] = other._value - # - # properties_self['name'] = self._name - # properties_other['name'] = other._name - for p in d_self: if p in self._exclude_from_equals: continue From b9bd1cf53108c4f37bafabc717a9e95b6dd00e5a Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 23 Jun 2021 18:16:29 -0700 Subject: [PATCH 050/234] remove unused import --- allensdk/brain_observatory/behavior/data_files/stimulus_file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/allensdk/brain_observatory/behavior/data_files/stimulus_file.py b/allensdk/brain_observatory/behavior/data_files/stimulus_file.py index 062db67f9..3feeb0378 100644 --- a/allensdk/brain_observatory/behavior/data_files/stimulus_file.py +++ b/allensdk/brain_observatory/behavior/data_files/stimulus_file.py @@ -1,5 +1,5 @@ import json -from typing import Dict, Union, Optional +from typing import Dict, Union from pathlib import Path from cachetools import cached, LRUCache From 3027e0925ca990157d3a9c128a07122453a326a8 Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 23 Jun 2021 18:17:25 -0700 Subject: [PATCH 051/234] make type more explicit --- .../behavior/data_objects/base/_data_object_abc.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py index 9f2df514e..e78801591 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py @@ -2,8 +2,6 @@ from collections import deque from typing import Any, Optional, Set -from pynwb import NWBFile - from allensdk.brain_observatory.comparison_utils import compare_fields @@ -16,7 +14,7 @@ class DataObject(abc.ABC): """ def __init__(self, name: str, value: Any, - exclude_from_equals: Optional[Set] = None): + exclude_from_equals: Optional[Set[str]] = None): """ :param name Name From a679c405769d5521a18b1a86b0a97c0565fa480f Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 23 Jun 2021 18:18:44 -0700 Subject: [PATCH 052/234] use dict instead of {} --- .../behavior/data_objects/base/_data_object_abc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py index e78801591..5c05a30b2 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py @@ -77,7 +77,7 @@ def to_dict(self) -> dict: >>> a = A() >>> a.to_dict() == {'a': {'b': '!'}, 'prop2': '@'} """ - res = {} + res = dict() q = deque([(self._name, self, [])]) while q: @@ -107,7 +107,7 @@ def _get_keys_and_values(value: DataObject): if properties: # it's nested - cur[value._name] = {} + cur[value._name] = dict() for p in properties: q.append(p) else: From 4cbb2135cd59e6273c9eac41cc5052396fffc481 Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 23 Jun 2021 18:28:07 -0700 Subject: [PATCH 053/234] moves readable, writable interfaces into single module --- .../behavior/behavior_session.py | 21 +--- .../data_objects/base/readable_interfaces.py | 106 ++++++++++++++++++ .../base/readable_interfaces/__init__.py | 0 .../internal_readable_interface.py | 21 ---- .../json_readable_interface.py | 19 ---- .../lims_readable_interface.py | 20 ---- .../nwb_readable_interface.py | 25 ----- .../stimulus_file_readable_interface.py | 18 --- .../sync_file_readable_interface.py | 18 --- ...le_interface.py => writable_interfaces.py} | 18 ++- .../base/writable_interfaces/__init__.py | 0 .../json_writable_interface.py | 21 ---- .../data_objects/cell_specimen_table.py | 14 +-- .../behavior_metadata/behavior_metadata.py | 22 +--- .../behavior_metadata/behavior_session_id.py | 14 +-- .../behavior_session_uuid.py | 9 +- .../behavior_metadata/date_of_acquisition.py | 14 +-- .../behavior_metadata/equipment_name.py | 14 +-- .../metadata/behavior_metadata/foraging_id.py | 11 +- .../behavior_metadata/session_type.py | 10 +- .../behavior_metadata/stimulus_frame_rate.py | 10 +- .../metadata/behavior_ophys_metadata.py | 14 +-- .../emission_lambda.py | 2 +- .../experiment_container_id.py | 12 +- .../field_of_view_shape.py | 12 +- .../imaging_depth.py | 12 +- .../imaging_plane.py | 12 +- .../imaging_plane_group.py | 10 +- .../ophys_experiment_metadata.py | 12 +- .../ophys_session_id.py | 12 +- .../ophys_experiment_metadata/project_code.py | 2 +- .../metadata/subject_metadata/age.py | 14 +-- .../metadata/subject_metadata/driver_line.py | 14 +-- .../subject_metadata/full_genotype.py | 14 +-- .../metadata/subject_metadata/mouse_id.py | 14 +-- .../subject_metadata/reporter_line.py | 14 +-- .../metadata/subject_metadata/sex.py | 14 +-- .../subject_metadata/subject_metadata.py | 21 +--- .../running_speed/running_acquisition.py | 18 +-- .../running_speed/running_speed.py | 21 +--- .../stimulus_timestamps.py | 29 ++--- 41 files changed, 238 insertions(+), 440 deletions(-) create mode 100644 allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces.py delete mode 100644 allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/__init__.py delete mode 100644 allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/internal_readable_interface.py delete mode 100644 allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/json_readable_interface.py delete mode 100644 allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/lims_readable_interface.py delete mode 100644 allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/nwb_readable_interface.py delete mode 100644 allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/stimulus_file_readable_interface.py delete mode 100644 allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/sync_file_readable_interface.py rename allensdk/brain_observatory/behavior/data_objects/base/{writable_interfaces/nwb_writable_interface.py => writable_interfaces.py} (56%) delete mode 100644 allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/__init__.py delete mode 100644 allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/json_writable_interface.py diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index 8245ded18..a803da08d 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -8,21 +8,12 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_files import StimulusFile -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .internal_readable_interface import \ - InternalReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ - JsonWritableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.nwb_writable_interface import \ - NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + InternalReadableInterface, JsonReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .writable_interfaces import \ + JsonWritableInterface, NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_metadata import \ BehaviorMetadata diff --git a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces.py new file mode 100644 index 000000000..237eaf6b2 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces.py @@ -0,0 +1,106 @@ +import abc + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_objects import DataObject + + +class InternalReadableInterface(abc.ABC): + """Marks a data object as readable from a variety of internal data sources + """ + @classmethod + @abc.abstractmethod + def from_internal(cls, *args) -> "DataObject": # pragma: no cover + """Populate a DataObject from various internal data sources + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + # Example: + # return cls(name="my_data_object", value=42) + raise NotImplementedError() + + +class JsonReadableInterface(abc.ABC): + """Marks a data object as readable from json""" + @classmethod + @abc.abstractmethod + def from_json(cls, dict_repr: dict) -> "DataObject": # pragma: no cover + """Populates a DataFile from a JSON compatible dict (likely parsed by + argschema) + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + raise NotImplementedError() + + +class LimsReadableInterface(abc.ABC): + """Marks a data object as readable from LIMS""" + @classmethod + @abc.abstractmethod + def from_lims(cls, *args) -> "DataObject": # pragma: no cover + """Populate a DataObject from an internal database (likely LIMS) + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + # Example: + # return cls(name="my_data_object", value=42) + raise NotImplementedError() + + +class NwbReadableInterface(abc.ABC): + """Marks a data object as readable from NWB""" + @classmethod + @abc.abstractmethod + def from_nwb(cls, nwbfile: NWBFile) -> "DataObject": # pragma: no cover + """Populate a DataObject from a pyNWB file object. + + Parameters + ---------- + nwbfile: + The file object (NWBFile) of a pynwb dataset file. + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + raise NotImplementedError() + + +class StimulusFileReadableInterface(abc.ABC): + """Marks a data object as readable from stimulus file""" + @classmethod + @abc.abstractmethod + def from_stimulus_file(cls, *args) -> "DataObject": + """Populate a DataObject from the stimulus file + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + raise NotImplementedError() + + +class SyncFileReadableInterface(abc.ABC): + """Marks a data object as readable from sync file""" + @classmethod + @abc.abstractmethod + def from_sync_file(cls, *args) -> "DataObject": + """Populate a DataObject from the sync file + + Returns + ------- + DataObject: + An instantiated DataObject which has `name` and `value` properties + """ + raise NotImplementedError() \ No newline at end of file diff --git a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/__init__.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/internal_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/internal_readable_interface.py deleted file mode 100644 index adaa6af61..000000000 --- a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/internal_readable_interface.py +++ /dev/null @@ -1,21 +0,0 @@ -import abc - -from allensdk.brain_observatory.behavior.data_objects import DataObject - - -class InternalReadableInterface(abc.ABC): - """Marks a data object as readable from a variety of internal data sources - """ - @classmethod - @abc.abstractmethod - def from_internal(cls, *args) -> "DataObject": # pragma: no cover - """Populate a DataObject from various internal data sources - - Returns - ------- - DataObject: - An instantiated DataObject which has `name` and `value` properties - """ - # Example: - # return cls(name="my_data_object", value=42) - raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/json_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/json_readable_interface.py deleted file mode 100644 index 8421c94cc..000000000 --- a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/json_readable_interface.py +++ /dev/null @@ -1,19 +0,0 @@ -import abc - -from allensdk.brain_observatory.behavior.data_objects import DataObject - - -class JsonReadableInterface(abc.ABC): - """Marks a data object as readable from json""" - @classmethod - @abc.abstractmethod - def from_json(cls, dict_repr: dict) -> "DataObject": # pragma: no cover - """Populates a DataFile from a JSON compatible dict (likely parsed by - argschema) - - Returns - ------- - DataObject: - An instantiated DataObject which has `name` and `value` properties - """ - raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/lims_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/lims_readable_interface.py deleted file mode 100644 index 88ee206a6..000000000 --- a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/lims_readable_interface.py +++ /dev/null @@ -1,20 +0,0 @@ -import abc - -from allensdk.brain_observatory.behavior.data_objects import DataObject - - -class LimsReadableInterface(abc.ABC): - """Marks a data object as readable from LIMS""" - @classmethod - @abc.abstractmethod - def from_lims(cls, *args) -> "DataObject": # pragma: no cover - """Populate a DataObject from an internal database (likely LIMS) - - Returns - ------- - DataObject: - An instantiated DataObject which has `name` and `value` properties - """ - # Example: - # return cls(name="my_data_object", value=42) - raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/nwb_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/nwb_readable_interface.py deleted file mode 100644 index 4f38b38c9..000000000 --- a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/nwb_readable_interface.py +++ /dev/null @@ -1,25 +0,0 @@ -import abc - -from pynwb import NWBFile - -from allensdk.brain_observatory.behavior.data_objects import DataObject - - -class NwbReadableInterface(abc.ABC): - """Marks a data object as readable from NWB""" - @classmethod - @abc.abstractmethod - def from_nwb(cls, nwbfile: NWBFile) -> "DataObject": # pragma: no cover - """Populate a DataObject from a pyNWB file object. - - Parameters - ---------- - nwbfile: - The file object (NWBFile) of a pynwb dataset file. - - Returns - ------- - DataObject: - An instantiated DataObject which has `name` and `value` properties - """ - raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/stimulus_file_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/stimulus_file_readable_interface.py deleted file mode 100644 index 9b2ec7507..000000000 --- a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/stimulus_file_readable_interface.py +++ /dev/null @@ -1,18 +0,0 @@ -import abc - -from allensdk.brain_observatory.behavior.data_objects import DataObject - - -class StimulusFileReadableInterface(abc.ABC): - """Marks a data object as readable from stimulus file""" - @classmethod - @abc.abstractmethod - def from_stimulus_file(cls, *args) -> "DataObject": - """Populate a DataObject from the stimulus file - - Returns - ------- - DataObject: - An instantiated DataObject which has `name` and `value` properties - """ - raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/sync_file_readable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/sync_file_readable_interface.py deleted file mode 100644 index ec2587a99..000000000 --- a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces/sync_file_readable_interface.py +++ /dev/null @@ -1,18 +0,0 @@ -import abc - -from allensdk.brain_observatory.behavior.data_objects import DataObject - - -class SyncFileReadableInterface(abc.ABC): - """Marks a data object as readable from sync file""" - @classmethod - @abc.abstractmethod - def from_sync_file(cls, *args) -> "DataObject": - """Populate a DataObject from the sync file - - Returns - ------- - DataObject: - An instantiated DataObject which has `name` and `value` properties - """ - raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces.py similarity index 56% rename from allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py rename to allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces.py index 408be8f39..45d6319b3 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/nwb_writable_interface.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces.py @@ -2,7 +2,21 @@ from pynwb import NWBFile -from allensdk.brain_observatory.behavior.data_objects import DataObject + +class JsonWritableInterface(abc.ABC): + """Marks a data object as writable to NWB""" + @abc.abstractmethod + def to_json(self) -> dict: # pragma: no cover + """Given an already populated DataObject, return the dict that + when used with the `from_json()` classmethod would produce the same + DataObject + + Returns + ------- + dict: + The JSON (in dict form) that would produce the DataObject. + """ + raise NotImplementedError() class NwbWritableInterface(abc.ABC): @@ -23,4 +37,4 @@ def to_nwb(self, nwbfile: NWBFile, *args) -> NWBFile: # pragma: no cover An NWB file object that has had data from the DataObject added to it. """ - raise NotImplementedError() + raise NotImplementedError() \ No newline at end of file diff --git a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/__init__.py b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/json_writable_interface.py b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/json_writable_interface.py deleted file mode 100644 index 6b50b4f83..000000000 --- a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces/json_writable_interface.py +++ /dev/null @@ -1,21 +0,0 @@ -import abc - -from pynwb import NWBFile - -from allensdk.brain_observatory.behavior.data_objects import DataObject - - -class JsonWritableInterface(abc.ABC): - """Marks a data object as writable to NWB""" - @abc.abstractmethod - def to_json(self) -> dict: # pragma: no cover - """Given an already populated DataObject, return the dict that - when used with the `from_json()` classmethod would produce the same - DataObject - - Returns - ------- - dict: - The JSON (in dict form) that would produce the DataObject. - """ - raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py index 84003848b..13ab88eb6 100644 --- a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py +++ b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py @@ -6,16 +6,10 @@ import allensdk.brain_observatory.roi_masks as roi from allensdk.brain_observatory.behavior.data_objects import DataObject from allensdk.brain_observatory.behavior.data_objects.base \ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base \ - .readable_interfaces.lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base \ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base \ - .writable_interfaces.nwb_writable_interface import \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .writable_interfaces import \ NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_ophys_metadata import \ diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index 1922fd2c1..43d38a78d 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -8,22 +8,12 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject, \ StimulusTimestamps, BehaviorSessionId -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .internal_readable_interface \ - import \ - InternalReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ - JsonWritableInterface -from allensdk.brain_observatory.behavior.data_objects.base.writable_interfaces\ - .nwb_writable_interface import \ - NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + InternalReadableInterface, JsonReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .writable_interfaces import \ + JsonWritableInterface, NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_session_uuid import \ BehaviorSessionUUID diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py index 17d97c79b..058462494 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_id.py @@ -3,17 +3,11 @@ from cachetools import cached, LRUCache from cachetools.keys import hashkey +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ + .writable_interfaces import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin from allensdk.brain_observatory.behavior.data_objects import DataObject diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py index d4bd610ea..4c2726354 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py @@ -5,12 +5,9 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .stimulus_file_readable_interface import \ - StimulusFileReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + NwbReadableInterface, StimulusFileReadableInterface class BehaviorSessionUUID(DataObject, StimulusFileReadableInterface, diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py index 76cea636d..4ec85e303 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py @@ -6,17 +6,11 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ + .writable_interfaces import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py index 0763a4fc3..2e06365f6 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py @@ -1,17 +1,11 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ + .writable_interfaces import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py index 3df29a668..004b51237 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py @@ -3,14 +3,11 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ + .writable_interfaces import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py index 882c6e6ed..20d53bf7c 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py @@ -2,13 +2,9 @@ from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .stimulus_file_readable_interface \ - import \ - StimulusFileReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + NwbReadableInterface, StimulusFileReadableInterface class SessionType(DataObject, StimulusFileReadableInterface, diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py index e6a49a0c7..13b7bd7b5 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py @@ -2,13 +2,9 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject, \ StimulusTimestamps -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .stimulus_file_readable_interface \ - import \ - StimulusFileReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + NwbReadableInterface, StimulusFileReadableInterface class StimulusFrameRate(DataObject, StimulusFileReadableInterface, diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py index 116ce4358..1b0c64ea1 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py @@ -4,17 +4,11 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject, \ BehaviorSessionId +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + InternalReadableInterface, JsonReadableInterface, NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.internal_readable_interface import \ - InternalReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.nwb_writable_interface import \ + .writable_interfaces import \ NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_metadata import \ diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/emission_lambda.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/emission_lambda.py index a03bc8fbb..3b1142698 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/emission_lambda.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/emission_lambda.py @@ -2,7 +2,7 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ + .readable_interfaces import \ NwbReadableInterface diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/experiment_container_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/experiment_container_id.py index d6d0ec29f..dc358de3e 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/experiment_container_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/experiment_container_id.py @@ -1,15 +1,9 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/field_of_view_shape.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/field_of_view_shape.py index c02074102..f085e4aca 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/field_of_view_shape.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/field_of_view_shape.py @@ -1,15 +1,9 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_depth.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_depth.py index c0efd9707..f5b265a2d 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_depth.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_depth.py @@ -1,15 +1,9 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_plane.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_plane.py index 7c9414d62..643ae02b7 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_plane.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_plane.py @@ -3,15 +3,9 @@ from allensdk.brain_observatory.behavior.data_files import SyncFile from allensdk.brain_observatory.behavior.data_objects import DataObject, \ StimulusTimestamps -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.internal_readable_interface import \ - InternalReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + InternalReadableInterface, JsonReadableInterface, NwbReadableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/imaging_plane_group.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/imaging_plane_group.py index 51ff376ff..a151f14ea 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/imaging_plane_group.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/imaging_plane_group.py @@ -2,14 +2,8 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject from allensdk.brain_observatory.behavior.data_objects.base \ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base \ - .readable_interfaces.lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base \ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py index 756be1b21..42cac9699 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py @@ -4,15 +4,9 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.internal_readable_interface import \ - InternalReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + InternalReadableInterface, JsonReadableInterface, NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.emission_lambda import \ EmissionLambda diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_session_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_session_id.py index f29e9060f..ea5a8e33a 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_session_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_session_id.py @@ -1,15 +1,9 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/project_code.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/project_code.py index 7c76c6d61..60216326e 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/project_code.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/project_code.py @@ -1,6 +1,6 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.lims_readable_interface import \ + .readable_interfaces import \ LimsReadableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py index d7289779f..8cfcf7247 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py @@ -5,17 +5,11 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ + .writable_interfaces import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py index dfc84a04e..d9c519384 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py @@ -3,17 +3,11 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ + .writable_interfaces import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin, \ OneOrMoreResultExpectedError diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py index 4b6fe8b06..bc8ca187f 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py @@ -4,17 +4,11 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ + .writable_interfaces import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py index 7b02098f4..a76c30e59 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py @@ -1,17 +1,11 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ + .writable_interfaces import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py index 49f5a36ec..ef01a916a 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py @@ -4,17 +4,11 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ + .writable_interfaces import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin, \ OneOrMoreResultExpectedError diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py index 29437bbe0..aa81242fb 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/sex.py @@ -1,17 +1,11 @@ from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ + .writable_interfaces import \ JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py index 15d2fea84..6aa531e6a 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py @@ -4,21 +4,12 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject, \ BehaviorSessionId -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ - JsonWritableInterface -from allensdk.brain_observatory.behavior.data_objects.base.writable_interfaces\ - .nwb_writable_interface import \ - NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .writable_interfaces import \ + JsonWritableInterface, NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.metadata\ .subject_metadata.age import \ Age diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py index 1a211baec..2f640e158 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_acquisition.py @@ -10,18 +10,12 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ - JsonWritableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.nwb_writable_interface import \ - NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + LimsReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .writable_interfaces import \ + JsonWritableInterface, NwbWritableInterface from allensdk.internal.api import PostgresQueryMixin from allensdk.brain_observatory.behavior.data_objects import ( DataObject, StimulusTimestamps diff --git a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py index 123725a91..eafe858d2 100644 --- a/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py +++ b/allensdk/brain_observatory/behavior/data_objects/running_speed/running_speed.py @@ -10,21 +10,12 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ - JsonWritableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.nwb_writable_interface import \ - NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .writable_interfaces import \ + JsonWritableInterface, NwbWritableInterface from allensdk.core.exceptions import DataFrameIndexError from allensdk.internal.api import PostgresQueryMixin from allensdk.brain_observatory.behavior.data_objects import ( diff --git a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py index caa7e6f11..2308df3a2 100644 --- a/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py +++ b/allensdk/brain_observatory/behavior/data_objects/stimulus_timestamps/stimulus_timestamps.py @@ -8,32 +8,17 @@ from pynwb import NWBFile, ProcessingModule from pynwb.base import TimeSeries -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.json_readable_interface import \ - JsonReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.lims_readable_interface import \ - LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces.nwb_readable_interface import \ - NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .stimulus_file_readable_interface \ - import \ - StimulusFileReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base.readable_interfaces\ - .sync_file_readable_interface import \ - SyncFileReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface, \ + StimulusFileReadableInterface, SyncFileReadableInterface from allensdk.brain_observatory.behavior.data_objects import DataObject from allensdk.brain_observatory.behavior.data_files import ( StimulusFile, SyncFile ) -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.json_writable_interface import \ - JsonWritableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces.nwb_writable_interface import \ - NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.base \ + .writable_interfaces import \ + JsonWritableInterface, NwbWritableInterface from allensdk.brain_observatory.behavior.data_objects.stimulus_timestamps.timestamps_processing import ( # noqa: E501 get_behavior_stimulus_timestamps, get_ophys_stimulus_timestamps ) From 68842692e89dc31567b8a50ab119009bd3729c09 Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 23 Jun 2021 18:30:20 -0700 Subject: [PATCH 054/234] rename variable to avoid naming confusion --- .../behavior/data_objects/metadata/behavior_ophys_metadata.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py index 1b0c64ea1..ebad12667 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py @@ -94,7 +94,7 @@ def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorOphysMetadata": def to_nwb(self, nwbfile: NWBFile) -> NWBFile: self._behavior_metadata.subject_metadata.to_nwb(nwbfile=nwbfile) - OphysBehaviorMetadata = load_pynwb_extension( + nwb_extension = load_pynwb_extension( OphysBehaviorMetadataSchema, 'ndx-aibs-behavior-ophys') behavior_meta = self._behavior_metadata @@ -107,7 +107,7 @@ def to_nwb(self, nwbfile: NWBFile) -> NWBFile: imaging_plane_group_count = 0 imaging_plane_group = -1 - nwb_metadata = OphysBehaviorMetadata( + nwb_metadata = nwb_extension( name='metadata', ophys_session_id=ophys_meta.ophys_session_id, field_of_view_width=ophys_meta.field_of_view_shape.width, From af710e69ae5b0c4f774a1742873295a4bc18f476 Mon Sep 17 00:00:00 2001 From: aamster Date: Thu, 24 Jun 2021 07:57:03 -0700 Subject: [PATCH 055/234] add tests for data object --- .../data_objects/base/_data_object_abc.py | 10 +-- .../brain_observatory/comparison_utils.py | 12 ++- .../data_objects/base/test_data_object.py | 81 +++++++++++++++++++ 3 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/base/test_data_object.py diff --git a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py index 5c05a30b2..0b0605472 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py @@ -66,7 +66,7 @@ def to_dict(self) -> dict: >>> class A(DataObject): ... def __init__(self, b: B): - ... super().__init__(name='simple', value=self) + ... super().__init__(name='a', value=self) ... self._b = b ... @property ... def prop1(self): @@ -74,7 +74,7 @@ def to_dict(self) -> dict: ... @property ... def prop2(self): ... return '@' - >>> a = A() + >>> a = A(b=B()) >>> a.to_dict() == {'a': {'b': '!'}, 'prop2': '@'} """ res = dict() @@ -137,14 +137,12 @@ def __eq__(self, other: "DataObject"): d_other = other.to_dict() for p in d_self: - if p in self._exclude_from_equals: - continue - x1 = d_self[p] x2 = d_other[p] try: - compare_fields(x1=x1, x2=x2) + compare_fields(x1=x1, x2=x2, + ignore_keys=self._exclude_from_equals) except AssertionError: return False return True diff --git a/allensdk/brain_observatory/comparison_utils.py b/allensdk/brain_observatory/comparison_utils.py index 4df97759e..8f61ab231 100644 --- a/allensdk/brain_observatory/comparison_utils.py +++ b/allensdk/brain_observatory/comparison_utils.py @@ -1,6 +1,6 @@ import datetime import math -from typing import Any +from typing import Any, Optional, Set import SimpleITK as sitk import numpy as np @@ -9,7 +9,8 @@ from pandas.util.testing import assert_frame_equal -def compare_fields(x1: Any, x2: Any, err_msg=""): +def compare_fields(x1: Any, x2: Any, err_msg="", + ignore_keys: Optional[Set[str]] = None): """Helper function to compare if two fields (attributes) are equal to one another. @@ -22,7 +23,12 @@ def compare_fields(x1: Any, x2: Any, err_msg=""): err_msg : str, optional The error message to display if two compared fields do not equal one another, by default "" (an empty string) + ignore_keys + For dictionary comparison, ignore these keys """ + if ignore_keys is None: + ignore_keys = set() + if isinstance(x1, pd.DataFrame): try: assert_frame_equal(x1, x2, check_like=True) @@ -54,6 +60,8 @@ def compare_fields(x1: Any, x2: Any, err_msg=""): assert x1 == x2, err_msg elif isinstance(x1, (dict,)): for key in set(x1.keys()).union(set(x2.keys())): + if key in ignore_keys: + continue key_err_msg = f"Mismatch when checking key {key}. {err_msg}" compare_fields(x1[key], x2[key], err_msg=key_err_msg) else: diff --git a/allensdk/test/brain_observatory/behavior/data_objects/base/test_data_object.py b/allensdk/test/brain_observatory/behavior/data_objects/base/test_data_object.py new file mode 100644 index 000000000..852f2f8b5 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/base/test_data_object.py @@ -0,0 +1,81 @@ +import pytest + +from allensdk.brain_observatory.behavior.data_objects import DataObject + + +class TestDataObject: + def test_to_dict_simple(self): + class Simple(DataObject): + def __init__(self): + super().__init__(name='simple', value=1) + s = Simple() + assert s.to_dict() == {'simple': 1} + + def test_to_dict_nested(self): + class B(DataObject): + def __init__(self): + super().__init__(name='b', value='!') + + class A(DataObject): + def __init__(self, b: B): + super().__init__(name='a', value=self) + self._b = b + + @property + def prop1(self): + return self._b + + @property + def prop2(self): + return '@' + a = A(b=B()) + assert a.to_dict() == {'a': {'b': '!', 'prop2': '@'}} + + def test_to_dict_double_nested(self): + class C(DataObject): + def __init__(self): + super().__init__(name='c', value='!!!') + + class B(DataObject): + def __init__(self, c: C): + super().__init__(name='b', value=self) + self._c = c + + @property + def prop1(self): + return self._c + + @property + def prop2(self): + return '!!' + + class A(DataObject): + def __init__(self, b: B): + super().__init__(name='a', value=self) + self._b = b + + @property + def prop1(self): + return self._b + + @property + def prop2(self): + return '@' + + a = A(b=B(c=C())) + assert a.to_dict() == {'a': {'b': {'c': '!!!', 'prop2': '!!'}, + 'prop2': '@'}} + + def test_not_equals(self): + s1 = DataObject(name='s1', value=1) + s2 = DataObject(name='s1', value='1') + assert s1 != s2 + + def test_exclude_equals(self): + s1 = DataObject(name='s1', value=1, exclude_from_equals={'value'}) + s2 = DataObject(name='s1', value='1') + assert s1 == s2 + + def test_cannot_compare(self): + with pytest.raises(NotImplementedError): + assert DataObject(name='foo', value=1) == 1 From 2b487b92d85f80cce50408e28290ca51b872b3ea Mon Sep 17 00:00:00 2001 From: aamster Date: Thu, 24 Jun 2021 12:23:20 -0700 Subject: [PATCH 056/234] Move write behavior meta test to new module Adds roundtrip for test --- .../test_behavior_metadata.py | 28 ++++++++++++++++++- .../test_behavior_ophys_metadata.py | 0 .../test_behavior_ophys_data_xforms.py | 8 ++---- .../behavior/test_write_behavior_nwb.py | 15 ---------- 4 files changed, 30 insertions(+), 21 deletions(-) rename allensdk/test/brain_observatory/behavior/data_objects/metadata/{behavior_ophys_metadata => }/test_behavior_ophys_metadata.py (100%) diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py index ec2a43635..63838e0ee 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py @@ -2,6 +2,7 @@ import pickle import uuid +import pynwb import pytest import pytz @@ -48,7 +49,7 @@ SubjectMetadata -class TestBehaviorMetadata: +class BehaviorMetaTestCase: @classmethod def setup_class(cls): cls.meta = cls._get_meta() @@ -81,6 +82,8 @@ def _get_meta(): ) return behavior_meta + +class TestBehaviorMetadata(BehaviorMetaTestCase): def test_cre_line(self): """Tests that cre_line properly parsed from driver_line""" fg = FullGenotype( @@ -233,3 +236,26 @@ def test_indicator_edge_cases(self, input_reporter_line, warning_msg, indicator = reporter_line.parse_indicator(warn=True) assert indicator is expected assert str(record[0].message) == warning_msg + + +class TestNWB(BehaviorMetaTestCase): + def setup_method(self, method): + self.nwbfile = pynwb.NWBFile( + session_description='asession', + identifier='afile', + session_start_time=self.meta.date_of_acquisition + ) + + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_add_behavior_only_metadata(self, roundtrip, + data_object_roundtrip_fixture): + self.meta.to_nwb(nwbfile=self.nwbfile) + + if roundtrip: + meta_obt = data_object_roundtrip_fixture( + self.nwbfile, BehaviorMetadata + ) + else: + meta_obt = BehaviorMetadata.from_nwb(nwbfile=self.nwbfile) + + assert self.meta == meta_obt diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata/test_behavior_ophys_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py similarity index 100% rename from allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata/test_behavior_ophys_metadata.py rename to allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py index 86f2b7813..f8acc7b0c 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py @@ -452,12 +452,10 @@ def dummy_delay(self): xform_init) def dummy_get_metadata(self): - test_beh_meta = TestBehaviorMetadata() - test_beh_meta.setup_class() - metadata = test_beh_meta.meta - metadata._equipment_name = EquipmentName( + test_beh_meta = TestBehaviorMetadata().meta + test_beh_meta._equipment_name = EquipmentName( equipment_name=equipment_name) - return metadata + return test_beh_meta ctx.setattr(BehaviorOphysDataTransforms, 'get_metadata', diff --git a/allensdk/test/brain_observatory/behavior/test_write_behavior_nwb.py b/allensdk/test/brain_observatory/behavior/test_write_behavior_nwb.py index a214a59cd..475fc90d1 100644 --- a/allensdk/test/brain_observatory/behavior/test_write_behavior_nwb.py +++ b/allensdk/test/brain_observatory/behavior/test_write_behavior_nwb.py @@ -171,21 +171,6 @@ def test_add_rewards(nwbfile, roundtrip, roundtripper, rewards): check_dtype=False) -def test_add_behavior_only_metadata(behavior_only_metadata_fixture): - - metadata = behavior_only_metadata_fixture - nwbfile = pynwb.NWBFile( - session_description='asession', - identifier='afile', - session_start_time=metadata.date_of_acquisition - ) - metadata.to_nwb(nwbfile=nwbfile) - - metadata_obt = BehaviorMetadata.from_nwb(nwbfile=nwbfile) - - assert metadata == metadata_obt - - @pytest.mark.parametrize('roundtrip', [True, False]) def test_add_task_parameters(nwbfile, roundtrip, roundtripper, task_parameters): From 2bfe9d9fe9fe15ec8cca052b4518c19f4cc13eda Mon Sep 17 00:00:00 2001 From: aamster Date: Thu, 24 Jun 2021 15:54:22 -0700 Subject: [PATCH 057/234] add from_internal, from_json tests --- .../metadata/test_behavior_ophys_metadata.py | 179 +++++++++++++----- 1 file changed, 133 insertions(+), 46 deletions(-) diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py index ed57991b9..a67bfd795 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py @@ -1,10 +1,16 @@ +from unittest.mock import create_autospec + import pandas as pd import pynwb import pytest +from allensdk.brain_observatory.behavior.data_objects import BehaviorSessionId from allensdk.brain_observatory.behavior.data_objects.cell_specimen_table \ import \ CellSpecimenTable +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.behavior_metadata import \ + BehaviorMetadata from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.session_type import \ SessionType @@ -40,55 +46,19 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.ophys_session_id import \ OphysSessionId -from allensdk.test.brain_observatory.behavior.data_objects.metadata\ +from allensdk.internal.api import PostgresQueryMixin +from allensdk.test.brain_observatory.behavior.data_objects.metadata \ .behavior_metadata.test_behavior_metadata import \ - TestBehaviorMetadata + TestBehaviorMetadata, BehaviorMetaTestCase -class TestBehaviorOphysMetadata: +class TestBO: + @classmethod + def setup_class(cls): + cls.meta = cls._get_meta() + def setup_method(self, method): self.meta = self._get_meta() - self.nwbfile = pynwb.NWBFile( - session_description='asession', - identifier=str(self.meta.ophys_metadata.ophys_experiment_id), - session_start_time=self.meta.behavior_metadata.date_of_acquisition - ) - - @pytest.mark.parametrize('roundtrip', [True, False]) - def test_write_nwb_read_no_cell_specimen_table( - self, roundtrip, data_object_roundtrip_fixture): - self.meta.to_nwb(nwbfile=self.nwbfile) - - with pytest.raises(RuntimeError): - if roundtrip: - data_object_roundtrip_fixture( - nwbfile=self.nwbfile, - data_object_cls=BehaviorOphysMetadata) - else: - self.meta.from_nwb(nwbfile=self.nwbfile) - - @pytest.mark.parametrize('meso', [True, False]) - @pytest.mark.parametrize('roundtrip', [True, False]) - def test_read_write_nwb(self, roundtrip, cell_specimen_table, - data_object_roundtrip_fixture, meso): - if meso: - self.meta = self._get_mesoscope_meta() - - self.meta.to_nwb(nwbfile=self.nwbfile) - - cell_specimen_table = pd.DataFrame(cell_specimen_table) - cell_specimen_table = CellSpecimenTable( - cell_specimen_table=cell_specimen_table) - cell_specimen_table.to_nwb(nwbfile=self.nwbfile, meta=self.meta) - - if roundtrip: - obt = data_object_roundtrip_fixture( - nwbfile=self.nwbfile, - data_object_cls=BehaviorOphysMetadata) - else: - obt = self.meta.from_nwb(nwbfile=self.nwbfile) - - assert obt == self.meta @staticmethod def _get_meta(): @@ -109,9 +79,8 @@ def _get_meta(): behavior_metadata = TestBehaviorMetadata() behavior_metadata.setup_class() - behavior_metadata = behavior_metadata.meta return BehaviorOphysMetadata( - behavior_metadata=behavior_metadata, + behavior_metadata=behavior_metadata.meta, ophys_metadata=ophys_meta ) @@ -139,3 +108,121 @@ def _get_mesoscope_meta(self): behavior_metadata=bo_meta.behavior_metadata, ophys_metadata=meso_meta ) + + +class TestInternal(TestBO): + @pytest.mark.parametrize('meso', [True, False]) + def test_from_internal(self, monkeypatch, meso): + mock_db_conn = create_autospec(PostgresQueryMixin, instance=True) + + behavior_session_id = self.meta.behavior_metadata.behavior_session_id + experiment_id = self.meta.ophys_metadata.ophys_experiment_id + + meta = self._get_mesoscope_meta() if meso else self.meta + + with monkeypatch.context() as m: + m.setattr(BehaviorSessionId, + 'from_lims', + lambda ophys_experiment_id, db: BehaviorSessionId( + behavior_session_id=behavior_session_id)) + m.setattr(BehaviorMetadata, + 'from_internal', + lambda behavior_session_id, lims_db: + meta.behavior_metadata) + if meso: + m.setattr(MesoscopeExperimentMetadata, + 'from_internal', + lambda ophys_experiment_id, lims_db: + meta.ophys_metadata) + else: + m.setattr(OphysExperimentMetadata, + 'from_internal', + lambda ophys_experiment_id, lims_db: + meta.ophys_metadata) + obt = BehaviorOphysMetadata.from_internal( + ophys_experiment_id=experiment_id, lims_db=mock_db_conn) + + if meso: + assert isinstance(obt.ophys_metadata, MesoscopeExperimentMetadata) + else: + assert isinstance(obt.ophys_metadata, OphysExperimentMetadata) + + assert obt == meta + + +class TestJson(TestBO): + @pytest.mark.parametrize('meso', [True, False]) + def test_from_json(self, monkeypatch, meso): + dict_repr = create_autospec(dict) + + meta = self._get_mesoscope_meta() if meso else self.meta + + with monkeypatch.context() as m: + m.setattr(BehaviorMetadata, + 'from_json', + lambda dict_repr: + meta.behavior_metadata) + if meso: + m.setattr(MesoscopeExperimentMetadata, + 'from_json', + lambda dict_repr: + meta.ophys_metadata) + else: + m.setattr(OphysExperimentMetadata, + 'from_json', + lambda dict_repr: + meta.ophys_metadata) + obt = BehaviorOphysMetadata.from_json(dict_repr=dict_repr) + + if meso: + assert isinstance(obt.ophys_metadata, MesoscopeExperimentMetadata) + else: + assert isinstance(obt.ophys_metadata, OphysExperimentMetadata) + + assert obt == meta + + +class TestNWB(TestBO): + def setup_method(self, method): + self.meta = self._get_meta() + self.nwbfile = pynwb.NWBFile( + session_description='asession', + identifier=str(self.meta.ophys_metadata.ophys_experiment_id), + session_start_time=self.meta.behavior_metadata.date_of_acquisition + ) + + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_write_nwb_read_no_cell_specimen_table( + self, roundtrip, data_object_roundtrip_fixture): + self.meta.to_nwb(nwbfile=self.nwbfile) + + with pytest.raises(RuntimeError): + if roundtrip: + data_object_roundtrip_fixture( + nwbfile=self.nwbfile, + data_object_cls=BehaviorOphysMetadata) + else: + self.meta.from_nwb(nwbfile=self.nwbfile) + + @pytest.mark.parametrize('meso', [True, False]) + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_read_write_nwb(self, roundtrip, cell_specimen_table, + data_object_roundtrip_fixture, meso): + if meso: + self.meta = self._get_mesoscope_meta() + + self.meta.to_nwb(nwbfile=self.nwbfile) + + cell_specimen_table = pd.DataFrame(cell_specimen_table) + cell_specimen_table = CellSpecimenTable( + cell_specimen_table=cell_specimen_table) + cell_specimen_table.to_nwb(nwbfile=self.nwbfile, meta=self.meta) + + if roundtrip: + obt = data_object_roundtrip_fixture( + nwbfile=self.nwbfile, + data_object_cls=BehaviorOphysMetadata) + else: + obt = self.meta.from_nwb(nwbfile=self.nwbfile) + + assert obt == self.meta From e10e39440f7425dec3824f28bec964b774abd10f Mon Sep 17 00:00:00 2001 From: aamster Date: Fri, 25 Jun 2021 10:05:16 -0700 Subject: [PATCH 058/234] Mesoscope check should be on the equipment, not session_type; Adds from_json test --- .../data_objects/base/_data_object_abc.py | 4 +- .../data_objects/cell_specimen_table.py | 13 +- .../behavior_metadata/behavior_metadata.py | 36 +- .../{equipment_name.py => equipment.py} | 25 +- .../behavior_metadata/session_type.py | 3 - .../metadata/behavior_ophys_metadata.py | 13 +- .../ophys_experiment_metadata.py | 2 +- .../behavior_ophys_data_transforms.py | 2 +- .../brain_observatory/behavior/conftest.py | 6 +- .../data_objects/base/test_data_object.py | 2 +- .../test_behavior_metadata.py | 6 +- .../metadata/test_behavior_ophys_metadata.py | 53 +- .../test_data/behavior_stimulus_file.pkl | Bin 0 -> 653 bytes .../behavior/data_objects/test_data/sync.h5 | Bin 0 -> 3448 bytes .../data_objects/test_data/test_input.json | 10211 ++++++++++++++++ .../test_behavior_ophys_data_xforms.py | 10 +- 16 files changed, 10305 insertions(+), 81 deletions(-) rename allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/{equipment_name.py => equipment.py} (68%) create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_data/behavior_stimulus_file.pkl create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_data/sync.h5 create mode 100755 allensdk/test/brain_observatory/behavior/data_objects/test_data/test_input.json diff --git a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py index 0b0605472..4a5ad7390 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py @@ -105,7 +105,7 @@ def _get_keys_and_values(value: DataObject): for p in path: cur = cur[p] - if properties: + if isinstance(value._value, DataObject): # it's nested cur[value._name] = dict() for p in properties: @@ -137,6 +137,8 @@ def __eq__(self, other: "DataObject"): d_other = other.to_dict() for p in d_self: + if p in self._exclude_from_equals: + continue x1 = d_self[p] x2 = d_other[p] diff --git a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py index 13ab88eb6..239fba7ea 100644 --- a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py +++ b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py @@ -11,6 +11,9 @@ from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces import \ NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.equipment import \ + EquipmentType from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_ophys_metadata import \ BehaviorOphysMetadata @@ -107,20 +110,20 @@ def to_nwb(self, nwbfile: NWBFile, meta: BehaviorOphysMetadata) -> NWBFile: imaging_plane_meta = meta.ophys_metadata.imaging_plane # Device: - device_name: str = metadata.equipment_name - if device_name.startswith("MESO"): + equipment = meta.behavior_metadata.equipment + if equipment.type == EquipmentType.MESOSCOPE: device_config = { - "name": device_name, + "name": equipment.value, "description": "Allen Brain Observatory - Mesoscope 2P Rig" } else: device_config = { - "name": device_name, + "name": equipment.value, "description": "Allen Brain Observatory - Scientifica 2P Rig", "manufacturer": "Scientifica" } nwbfile.create_device(**device_config) - device = nwbfile.get_device(device_name) + device = nwbfile.get_device(equipment.value) # FOV: fov_width = metadata.field_of_view_width diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index 43d38a78d..2ef05bb68 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -21,8 +21,8 @@ .behavior_metadata.date_of_acquisition import \ DateOfAcquisition from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.equipment_name import \ - EquipmentName + .behavior_metadata.equipment import \ + Equipment from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.foraging_id import \ ForagingId @@ -188,7 +188,7 @@ class BehaviorMetadata(DataObject, InternalReadableInterface, def __init__(self, subject_metadata: SubjectMetadata, behavior_session_id: BehaviorSessionId, - equipment_name: EquipmentName, + equipment: Equipment, stimulus_frame_rate: StimulusFrameRate, session_type: SessionType, date_of_acquisition: DateOfAcquisition, @@ -196,7 +196,7 @@ def __init__(self, super().__init__(name='behavior_metadata', value=self) self._subject_metadata = subject_metadata self._behavior_session_id = behavior_session_id - self._equipment_name = equipment_name + self._equipment = equipment self._stimulus_frame_rate = stimulus_frame_rate self._session_type = session_type self._date_of_acquisition = date_of_acquisition @@ -212,7 +212,7 @@ def from_internal( ) -> "BehaviorMetadata": subject_metadata = SubjectMetadata.from_lims( behavior_session_id=behavior_session_id, lims_db=lims_db) - equipment_name = EquipmentName.from_lims( + equipment = Equipment.from_lims( behavior_session_id=behavior_session_id.value, lims_db=lims_db) stimulus_file = StimulusFile.from_lims( @@ -239,7 +239,7 @@ def from_internal( return cls( subject_metadata=subject_metadata, behavior_session_id=behavior_session_id, - equipment_name=equipment_name, + equipment=equipment, stimulus_frame_rate=stimulus_frame_rate, session_type=session_type, date_of_acquisition=date_of_acquisition, @@ -250,7 +250,7 @@ def from_internal( def from_json(cls, dict_repr: dict) -> "BehaviorMetadata": subject_metadata = SubjectMetadata.from_json(dict_repr=dict_repr) behavior_session_id = BehaviorSessionId.from_json(dict_repr=dict_repr) - equipment_name = EquipmentName.from_json(dict_repr=dict_repr) + equipment = Equipment.from_json(dict_repr=dict_repr) date_of_acquisition = DateOfAcquisition.from_json(dict_repr=dict_repr) stimulus_file = StimulusFile.from_json(dict_repr=dict_repr) @@ -266,7 +266,7 @@ def from_json(cls, dict_repr: dict) -> "BehaviorMetadata": return cls( subject_metadata=subject_metadata, behavior_session_id=behavior_session_id, - equipment_name=equipment_name, + equipment=equipment, stimulus_frame_rate=stimulus_frame_rate, session_type=session_type, date_of_acquisition=date_of_acquisition, @@ -278,7 +278,7 @@ def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorMetadata": subject_metadata = SubjectMetadata.from_nwb(nwbfile=nwbfile) behavior_session_id = BehaviorSessionId.from_nwb(nwbfile=nwbfile) - equipment_name = EquipmentName.from_nwb(nwbfile=nwbfile) + equipment = Equipment.from_nwb(nwbfile=nwbfile) stimulus_frame_rate = StimulusFrameRate.from_nwb(nwbfile=nwbfile) session_type = SessionType.from_nwb(nwbfile=nwbfile) date_of_acquisition = DateOfAcquisition.from_nwb(nwbfile=nwbfile) @@ -287,7 +287,7 @@ def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorMetadata": return cls( subject_metadata=subject_metadata, behavior_session_id=behavior_session_id, - equipment_name=equipment_name, + equipment=equipment, stimulus_frame_rate=stimulus_frame_rate, session_type=session_type, date_of_acquisition=date_of_acquisition, @@ -295,16 +295,16 @@ def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorMetadata": ) @property - def equipment_name(self) -> str: - return self._equipment_name.value + def equipment(self) -> Equipment: + return self._equipment @property def stimulus_frame_rate(self) -> float: return self._stimulus_frame_rate.value @property - def session_type(self) -> SessionType: - return self._session_type + def session_type(self) -> str: + return self._session_type.value @property def date_of_acquisition(self) -> datetime: @@ -335,13 +335,9 @@ def to_nwb(self, nwbfile: NWBFile) -> NWBFile: behavior_session_id=self.behavior_session_id, behavior_session_uuid=str(self.behavior_session_uuid), stimulus_frame_rate=self.stimulus_frame_rate, - session_type=self.session_type.value, - equipment_name=self.equipment_name + session_type=self.session_type, + equipment_name=self.equipment.value ) nwbfile.add_lab_meta_data(nwb_metadata) return nwbfile - - def __dict__(self): - props = self._get_properties() - diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment.py similarity index 68% rename from allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py rename to allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment.py index 2e06365f6..d1d9b9c78 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment_name.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment.py @@ -1,3 +1,5 @@ +from enum import Enum + from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_objects import DataObject @@ -10,14 +12,19 @@ from allensdk.internal.api import PostgresQueryMixin -class EquipmentName(DataObject, JsonReadableInterface, LimsReadableInterface, - NwbReadableInterface, JsonWritableInterface): +class EquipmentType(Enum): + MESOSCOPE = 'MESOSCOPE' + OTHER = 'OTHER' + + +class Equipment(DataObject, JsonReadableInterface, LimsReadableInterface, + NwbReadableInterface, JsonWritableInterface): """the name of the experimental rig.""" def __init__(self, equipment_name: str): super().__init__(name="equipment_name", value=equipment_name) @classmethod - def from_json(cls, dict_repr: dict) -> "EquipmentName": + def from_json(cls, dict_repr: dict) -> "Equipment": return cls(equipment_name=dict_repr["rig_name"]) def to_json(self) -> dict: @@ -25,7 +32,7 @@ def to_json(self) -> dict: @classmethod def from_lims(cls, behavior_session_id: int, - lims_db: PostgresQueryMixin) -> "EquipmentName": + lims_db: PostgresQueryMixin) -> "Equipment": query = f""" SELECT e.name AS device_name FROM behavior_sessions bs @@ -36,6 +43,14 @@ def from_lims(cls, behavior_session_id: int, return cls(equipment_name=equipment_name) @classmethod - def from_nwb(cls, nwbfile: NWBFile) -> "EquipmentName": + def from_nwb(cls, nwbfile: NWBFile) -> "Equipment": metadata = nwbfile.lab_meta_data['metadata'] return cls(equipment_name=metadata.equipment_name) + + @property + def type(self): + if self.value.startswith('MESO'): + et = EquipmentType.MESOSCOPE + else: + et = EquipmentType.OTHER + return et diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py index 20d53bf7c..67c43d230 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/session_type.py @@ -34,6 +34,3 @@ def from_stimulus_file( def from_nwb(cls, nwbfile: NWBFile) -> "SessionType": metadata = nwbfile.lab_meta_data['metadata'] return cls(session_type=metadata.session_type) - - def is_mesoscope(self): - return self.value.startswith('MESO') diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py index ebad12667..bc386e99f 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py @@ -13,6 +13,9 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_metadata import \ BehaviorMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.equipment import \ + EquipmentType from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.mesoscope_experiment_metadata\ .mesoscope_experiment_metadata import \ @@ -54,7 +57,7 @@ def from_internal(cls, ophys_experiment_id: int, behavior_metadata = BehaviorMetadata.from_internal( behavior_session_id=behavior_session_id, lims_db=lims_db) - if behavior_metadata.session_type.is_mesoscope(): + if behavior_metadata.equipment.type == EquipmentType.MESOSCOPE: ophys_metadata = MesoscopeExperimentMetadata.from_internal( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) else: @@ -68,7 +71,7 @@ def from_internal(cls, ophys_experiment_id: int, def from_json(cls, dict_repr: dict) -> "BehaviorOphysMetadata": behavior_metadata = BehaviorMetadata.from_json(dict_repr=dict_repr) - if behavior_metadata.session_type.is_mesoscope(): + if behavior_metadata.equipment.type == EquipmentType.MESOSCOPE: ophys_metadata = MesoscopeExperimentMetadata.from_json( dict_repr=dict_repr) else: @@ -82,7 +85,7 @@ def from_json(cls, dict_repr: dict) -> "BehaviorOphysMetadata": def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorOphysMetadata": behavior_metadata = BehaviorMetadata.from_nwb(nwbfile=nwbfile) - if behavior_metadata.session_type.is_mesoscope(): + if behavior_metadata.equipment.type == EquipmentType.MESOSCOPE: ophys_metadata = MesoscopeExperimentMetadata.from_nwb( nwbfile=nwbfile) else: @@ -117,8 +120,8 @@ def to_nwb(self, nwbfile: NWBFile) -> NWBFile: stimulus_frame_rate=behavior_meta.stimulus_frame_rate, experiment_container_id=ophys_meta.experiment_container_id, ophys_experiment_id=ophys_meta.ophys_experiment_id, - session_type=behavior_meta.session_type.value, - equipment_name=behavior_meta.equipment_name, + session_type=behavior_meta.session_type, + equipment_name=behavior_meta.equipment.value, imaging_depth=ophys_meta.imaging_depth, behavior_session_uuid=str(behavior_meta.behavior_session_uuid), behavior_session_id=behavior_meta.behavior_session_id diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py index 42cac9699..1e835f2fa 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py @@ -96,7 +96,7 @@ def from_json(cls, dict_repr: dict) -> "OphysExperimentMetadata": emission_lambda = EmissionLambda() field_of_view_shape = FieldOfViewShape.from_json(dict_repr=dict_repr) imaging_depth = ImagingDepth.from_json(dict_repr=dict_repr) - return cls( + return OphysExperimentMetadata( ophys_experiment_id=ophys_experiment_id, ophys_session_id=ophys_session_id, experiment_container_id=experiment_container_id, diff --git a/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py b/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py index 768fda34f..46b4e2b01 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_ophys_data_transforms.py @@ -163,7 +163,7 @@ def _load_stimulus_timestamps_and_delay(self): try: delay = aligner.monitor_delay except ValueError as ee: - equipment_name = self.get_metadata().equipment_name + equipment_name = self.get_metadata() warning_msg = 'Monitory delay calculation failed ' warning_msg += 'with ValueError\n' diff --git a/allensdk/test/brain_observatory/behavior/conftest.py b/allensdk/test/brain_observatory/behavior/conftest.py index 07afec431..74e5d2c1f 100644 --- a/allensdk/test/brain_observatory/behavior/conftest.py +++ b/allensdk/test/brain_observatory/behavior/conftest.py @@ -19,8 +19,8 @@ .behavior_metadata.date_of_acquisition import \ DateOfAcquisition from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.equipment_name import \ - EquipmentName + .behavior_metadata.equipment import \ + Equipment from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.session_type import \ SessionType @@ -222,7 +222,7 @@ def behavior_only_metadata_fixture(): behavior_meta = BehaviorMetadata( subject_metadata=subject_meta, behavior_session_id=BehaviorSessionId(behavior_session_id=4242), - equipment_name=EquipmentName(equipment_name='my_device'), + equipment=Equipment(equipment_name='my_device'), stimulus_frame_rate=StimulusFrameRate(stimulus_frame_rate=60.0), session_type=SessionType(session_type='Unknown'), date_of_acquisition=DateOfAcquisition( diff --git a/allensdk/test/brain_observatory/behavior/data_objects/base/test_data_object.py b/allensdk/test/brain_observatory/behavior/data_objects/base/test_data_object.py index 852f2f8b5..1ebdc7953 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/base/test_data_object.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/base/test_data_object.py @@ -72,7 +72,7 @@ def test_not_equals(self): assert s1 != s2 def test_exclude_equals(self): - s1 = DataObject(name='s1', value=1, exclude_from_equals={'value'}) + s1 = DataObject(name='s1', value=1, exclude_from_equals={'s1'}) s2 = DataObject(name='s1', value='1') assert s1 == s2 diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py index 63838e0ee..1bb587af2 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/behavior_metadata/test_behavior_metadata.py @@ -18,8 +18,8 @@ .behavior_metadata.date_of_acquisition import \ DateOfAcquisition from allensdk.brain_observatory.behavior.data_objects.metadata \ - .behavior_metadata.equipment_name import \ - EquipmentName + .behavior_metadata.equipment import \ + Equipment from allensdk.brain_observatory.behavior.data_objects.metadata \ .behavior_metadata.session_type import \ SessionType @@ -71,7 +71,7 @@ def _get_meta(): behavior_meta = BehaviorMetadata( subject_metadata=subject_meta, behavior_session_id=BehaviorSessionId(behavior_session_id=4242), - equipment_name=EquipmentName(equipment_name='my_device'), + equipment=Equipment(equipment_name='my_device'), stimulus_frame_rate=StimulusFrameRate(stimulus_frame_rate=60.0), session_type=SessionType(session_type='Unknown'), date_of_acquisition=DateOfAcquisition( diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py index a67bfd795..bb7c98e60 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py @@ -1,3 +1,5 @@ +import json +from pathlib import Path from unittest.mock import create_autospec import pandas as pd @@ -12,8 +14,8 @@ .behavior_metadata.behavior_metadata import \ BehaviorMetadata from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.session_type import \ - SessionType + .behavior_metadata.equipment import \ + Equipment from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_ophys_metadata import \ BehaviorOphysMetadata @@ -49,7 +51,7 @@ from allensdk.internal.api import PostgresQueryMixin from allensdk.test.brain_observatory.behavior.data_objects.metadata \ .behavior_metadata.test_behavior_metadata import \ - TestBehaviorMetadata, BehaviorMetaTestCase + TestBehaviorMetadata class TestBO: @@ -86,8 +88,8 @@ def _get_meta(): def _get_mesoscope_meta(self): bo_meta = self.meta - bo_meta.behavior_metadata._session_type = \ - SessionType(session_type='MESO.1') + bo_meta.behavior_metadata._equipment = \ + Equipment(equipment_name='MESO.1') ophys_experiment_metadata = bo_meta.ophys_metadata imaging_plane_group = ImagingPlaneGroup(plane_group_count=5, @@ -151,35 +153,28 @@ def test_from_internal(self, monkeypatch, meso): class TestJson(TestBO): + @classmethod + def setup_method(self, method): + dir = Path(__file__).parent.resolve() + test_data_dir = dir.parent / 'test_data' + with open(test_data_dir / 'test_input.json') as f: + dict_repr = json.load(f) + dict_repr = dict_repr['session_data'] + dict_repr['sync_file'] = str(test_data_dir / 'sync.h5') + dict_repr['behavior_stimulus_file'] = str(test_data_dir / + 'behavior_stimulus_file.pkl') + self.dict_repr = dict_repr + @pytest.mark.parametrize('meso', [True, False]) def test_from_json(self, monkeypatch, meso): - dict_repr = create_autospec(dict) - - meta = self._get_mesoscope_meta() if meso else self.meta - - with monkeypatch.context() as m: - m.setattr(BehaviorMetadata, - 'from_json', - lambda dict_repr: - meta.behavior_metadata) - if meso: - m.setattr(MesoscopeExperimentMetadata, - 'from_json', - lambda dict_repr: - meta.ophys_metadata) - else: - m.setattr(OphysExperimentMetadata, - 'from_json', - lambda dict_repr: - meta.ophys_metadata) - obt = BehaviorOphysMetadata.from_json(dict_repr=dict_repr) + if meso: + self.dict_repr['rig_name'] = 'MESO.1' + bom = BehaviorOphysMetadata.from_json(dict_repr=self.dict_repr) if meso: - assert isinstance(obt.ophys_metadata, MesoscopeExperimentMetadata) + assert isinstance(bom.ophys_metadata, MesoscopeExperimentMetadata) else: - assert isinstance(obt.ophys_metadata, OphysExperimentMetadata) - - assert obt == meta + assert isinstance(bom.ophys_metadata, OphysExperimentMetadata) class TestNWB(TestBO): diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_data/behavior_stimulus_file.pkl b/allensdk/test/brain_observatory/behavior/data_objects/test_data/behavior_stimulus_file.pkl new file mode 100644 index 0000000000000000000000000000000000000000..20d6103b210e7c812361c4037d68f3a8472f152e GIT binary patch literal 653 zcmb_Z+iuf95OuC?+ydne<u!)umhMMh3FN;%4Wldis;htwxHiU)!%ECv;`${qG>e(Eaf6p> zoU=Y|GK-ZiaBGa)4y*7IW#8k@Xf*o#i>x@9WpLO3F+3rRto@;I|H0#)!F``MsGm`h zh`l&H$F7S9PL7AXPU%aj9=UkzxY%Z9NoGSn)85W}Oeai7Q%D6N#d=*0!dUWI8+hW*xiP+0M*v zH-_k9sUM{k^i+yPX@#~TdMTm^Ev>W$4}ypX@zR3@FCM*k(dU`}jQOeuK|E;QygR@5 zd7uCL&inD-?3<&*kFQ;G+Zv6fuTNX0-I6r3$M0$Bu9colXa3%_kxThT$}@RsYe@h4#PJes1eC!#ORVEmB*&%H_+*zOUWY%f0_| z&+@#IYtQnvkmkn*bc`Xn{yJZZH_16NYQ8Mbmt*thN^9i=mYl$31s%w>M>dNwi(g~v z(WgYeMM8JBg80w0{#ns#m*|IggUG;_NcbBj#GfFcw@ixv3JJY&pZFdL{X``GArktI zuJ|<)`sp5s`45xO)*%q-xL2J2|aOI{1YVf z&`07QCZW|i@jIW2-u$`vM@jhcMe)y*(8E{6cjrV0--!P)34hCX;vXZS5Bwb}*gg)}C_+OLIJAV`ZBnka0e`YZL0tvn2MiBJ`3H|!b zAp9>$=-s!1sPB{XZwKLDBB96c1W`|u&`0h8;eSO!*GnMkCnWUAG6=taP;~qdh41yw>}HENH#%D45fF>z)*SYMc01N%-xZ;-4p>@7k46`*0k@`+g!Z|I1Yn z^;;79?291$Yb5;uM4cm{KRW=zpV6DXQ*-z0mEw$EQyt$^XzIhNW9s)6buVZ)V--3< zJ8rdOXEIcbG!2%Lfq=-JYBiJ-x-rKsFtU+VKaSwo7J^krHDl+`o>`8M-7t1ye=2#c zWmrbPY4w`}n5tqKl}&cZ7tLF>AqX2mX7EW2deR(UW9ZTL;)G~B9c@a21S ztL1c}>88g$@e|>V*Xe1!5X3>v4{C}*uD9QbL%&{EVK$ER+$qyh-Bu8_!z2zJ)}oGu z(f?Gt;d}d>NHwD%)W@+39vN;W*&cOAg^?dLv0L3LnI-Gq`as#Rl~*lQZEJ9_%ylG} zdg+q>qbSFpXKl71M}=*ljp+(|q3pn`|SwX?XJo?S#mlbP49{ EAIbSdCjbBd literal 0 HcmV?d00001 diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_data/test_input.json b/allensdk/test/brain_observatory/behavior/data_objects/test_data/test_input.json new file mode 100755 index 000000000..0ae28f85f --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/test_data/test_input.json @@ -0,0 +1,10211 @@ +{ + "log_level": "DEBUG", + "session_data": { + "ophys_experiment_id": 1234, + "ophys_session_id": 999, + "behavior_session_id": 1071270468, + "foraging_id": "968ff5ae-e0d5-4661-bb6d-242bee28c7ac", + "full_genotype": "Vip-IRES-Cre/wt;Ai148(TIT2L-GC6f-ICL-tTA2)/wt", + "reporter_line": [ + "Ai148(TIT2L-GC6f-ICL-tTA2)" + ], + "driver_line": [ + "Vip-IRES-Cre" + ], + "ophys_cell_segmentation_run_id": 1080628312, + "rig_name": "CAM2P.4", + "movie_height": 512, + "movie_width": 451, + "container_id": 5678, + "surface_2p_pixel_size_um": 0.78125, + "date_of_acquisition": "2020-12-17 10:01:12", + "external_specimen_name": 544261, + "targeted_structure": "VISp", + "targeted_depth": 175, + "stimulus_name": "OPHYS_6_images_B", + "sex": "F", + "age": "P156", + "eye_tracking_rig_geometry": { + "monitor_position_mm": [ + 118.6, + 86.2, + 31.6 + ], + "monitor_rotation_deg": [ + 0.0, + 0.0, + 0.0 + ], + "camera_position_mm": [ + 102.8, + 74.7, + 31.6 + ], + "camera_rotation_deg": [ + 0.0, + 0.0, + 2.8 + ], + "led_position": [ + 246.0, + 92.3, + 52.6 + ], + "equipment": "CAM2P.4" + }, + "eye_tracking_filepath": "/allen/programs/braintv/production/visualbehavior/prod4/specimen_1050612336/ophys_session_1071202230/eye_tracking/1071202230_ellipse.h5", + "events_file": "/allen/programs/braintv/production/visualbehavior/prod4/specimen_1050612336/ophys_session_1071202230/ophys_experiment_1071440875/1071440875_event.h5", + "imaging_plane_group": null, + "plane_group_count": 0, + "cell_specimen_table_dict": { + "cell_roi_id": { + "0": 1080639771, + "1": 1080639729, + "2": 1080639652, + "3": 1080639639, + "4": 1080639619, + "5": 1080639602, + "6": 1080639634, + "7": 1080639671, + "8": 1080639724, + "9": 1080639615, + "10": 1080639719, + "11": 1080639646, + "12": 1080639734, + "13": 1080639599, + "14": 1080639757, + "15": 1080639700, + "16": 1080639742, + "17": 1080639751, + "18": 1080639710, + "19": 1080639694, + "20": 1080639687, + "21": 1080639678, + "22": 1080639617, + "23": 1080639606, + "24": 1080639597, + "25": 1080639608, + "26": 1080639705, + "27": 1080639610, + "28": 1080639591, + "29": 1080639593, + "30": 1080639623, + "31": 1080639627, + "32": 1080639763, + "33": 1080639658, + "34": 1080639663 + }, + "cell_specimen_id": { + "0": 1086633380, + "1": 1086633339, + "2": 1086633332, + "3": 1086633316, + "4": 1086633303, + "5": 1086633291, + "6": 1086632579, + "7": 1086632521, + "8": 1086632450, + "9": 1086632408, + "10": 1086632371, + "11": 1086632312, + "12": 1086632294, + "13": 1086632264, + "14": 1086632192, + "15": 1086632159, + "16": 1086632005, + "17": 1086631914, + "18": 1086631720, + "19": 1086631620, + "20": 1086631567, + "21": 1086631514, + "22": 1086631455, + "23": 1086631390, + "24": 1086631342, + "25": 1086631288, + "26": 1086631205, + "27": 1086631138, + "28": 1086631077, + "29": 1086631018, + "30": 1086630818, + "31": 1086630755, + "32": 1086630685, + "33": 1086630543, + "34": 1086630477 + }, + "x": { + "0": 422, + "1": 185, + "2": 2, + "3": 165, + "4": 329, + "5": 214, + "6": 48, + "7": 305, + "8": 331, + "9": 23, + "10": 372, + "11": 270, + "12": 289, + "13": 398, + "14": 347, + "15": 225, + "16": 225, + "17": 223, + "18": 216, + "19": 361, + "20": 292, + "21": 429, + "22": 189, + "23": 298, + "24": 136, + "25": 111, + "26": 368, + "27": 252, + "28": 53, + "29": 310, + "30": 136, + "31": 301, + "32": 69, + "33": 169, + "34": 283 + }, + "y": { + "0": 147, + "1": 2, + "2": 336, + "3": 461, + "4": 491, + "5": 373, + "6": 448, + "7": 296, + "8": 2, + "9": 387, + "10": 2, + "11": 460, + "12": 147, + "13": 384, + "14": 53, + "15": 237, + "16": 102, + "17": 71, + "18": 338, + "19": 251, + "20": 255, + "21": 269, + "22": 391, + "23": 378, + "24": 381, + "25": 417, + "26": 355, + "27": 421, + "28": 422, + "29": 422, + "30": 471, + "31": 454, + "32": 224, + "33": 322, + "34": 321 + }, + "max_correction_up": { + "0": 20.0, + "1": 20.0, + "2": 20.0, + "3": 20.0, + "4": 20.0, + "5": 20.0, + "6": 20.0, + "7": 20.0, + "8": 20.0, + "9": 20.0, + "10": 20.0, + "11": 20.0, + "12": 20.0, + "13": 20.0, + "14": 20.0, + "15": 20.0, + "16": 20.0, + "17": 20.0, + "18": 20.0, + "19": 20.0, + "20": 20.0, + "21": 20.0, + "22": 20.0, + "23": 20.0, + "24": 20.0, + "25": 20.0, + "26": 20.0, + "27": 20.0, + "28": 20.0, + "29": 20.0, + "30": 20.0, + "31": 20.0, + "32": 20.0, + "33": 20.0, + "34": 20.0 + }, + "max_correction_right": { + "0": 10.0, + "1": 10.0, + "2": 10.0, + "3": 10.0, + "4": 10.0, + "5": 10.0, + "6": 10.0, + "7": 10.0, + "8": 10.0, + "9": 10.0, + "10": 10.0, + "11": 10.0, + "12": 10.0, + "13": 10.0, + "14": 10.0, + "15": 10.0, + "16": 10.0, + "17": 10.0, + "18": 10.0, + "19": 10.0, + "20": 10.0, + "21": 10.0, + "22": 10.0, + "23": 10.0, + "24": 10.0, + "25": 10.0, + "26": 10.0, + "27": 10.0, + "28": 10.0, + "29": 10.0, + "30": 10.0, + "31": 10.0, + "32": 10.0, + "33": 10.0, + "34": 10.0 + }, + "max_correction_down": { + "0": 10.0, + "1": 10.0, + "2": 10.0, + "3": 10.0, + "4": 10.0, + "5": 10.0, + "6": 10.0, + "7": 10.0, + "8": 10.0, + "9": 10.0, + "10": 10.0, + "11": 10.0, + "12": 10.0, + "13": 10.0, + "14": 10.0, + "15": 10.0, + "16": 10.0, + "17": 10.0, + "18": 10.0, + "19": 10.0, + "20": 10.0, + "21": 10.0, + "22": 10.0, + "23": 10.0, + "24": 10.0, + "25": 10.0, + "26": 10.0, + "27": 10.0, + "28": 10.0, + "29": 10.0, + "30": 10.0, + "31": 10.0, + "32": 10.0, + "33": 10.0, + "34": 10.0 + }, + "max_correction_left": { + "0": 0.0, + "1": 0.0, + "2": 0.0, + "3": 0.0, + "4": 0.0, + "5": 0.0, + "6": 0.0, + "7": 0.0, + "8": 0.0, + "9": 0.0, + "10": 0.0, + "11": 0.0, + "12": 0.0, + "13": 0.0, + "14": 0.0, + "15": 0.0, + "16": 0.0, + "17": 0.0, + "18": 0.0, + "19": 0.0, + "20": 0.0, + "21": 0.0, + "22": 0.0, + "23": 0.0, + "24": 0.0, + "25": 0.0, + "26": 0.0, + "27": 0.0, + "28": 0.0, + "29": 0.0, + "30": 0.0, + "31": 0.0, + "32": 0.0, + "33": 0.0, + "34": 0.0 + }, + "valid_roi": { + "0": false, + "1": false, + "2": false, + "3": false, + "4": false, + "5": true, + "6": true, + "7": true, + "8": false, + "9": true, + "10": false, + "11": false, + "12": true, + "13": true, + "14": false, + "15": true, + "16": true, + "17": true, + "18": true, + "19": true, + "20": true, + "21": true, + "22": true, + "23": true, + "24": true, + "25": true, + "26": true, + "27": true, + "28": true, + "29": false, + "30": false, + "31": false, + "32": true, + "33": true, + "34": true + }, + "height": { + "0": 13, + "1": 10, + "2": 14, + "3": 18, + "4": 15, + "5": 18, + "6": 12, + "7": 20, + "8": 9, + "9": 18, + "10": 19, + "11": 14, + "12": 19, + "13": 13, + "14": 21, + "15": 15, + "16": 18, + "17": 16, + "18": 21, + "19": 14, + "20": 18, + "21": 13, + "22": 17, + "23": 17, + "24": 14, + "25": 16, + "26": 13, + "27": 14, + "28": 18, + "29": 16, + "30": 19, + "31": 21, + "32": 27, + "33": 13, + "34": 16 + }, + "width": { + "0": 13, + "1": 18, + "2": 12, + "3": 12, + "4": 16, + "5": 15, + "6": 18, + "7": 11, + "8": 22, + "9": 13, + "10": 14, + "11": 15, + "12": 14, + "13": 16, + "14": 11, + "15": 14, + "16": 23, + "17": 13, + "18": 24, + "19": 13, + "20": 15, + "21": 18, + "22": 13, + "23": 14, + "24": 12, + "25": 15, + "26": 23, + "27": 13, + "28": 12, + "29": 12, + "30": 13, + "31": 13, + "32": 15, + "33": 15, + "34": 19 + }, + "mask_image_plane": { + "0": 0, + "1": 0, + "2": 0, + "3": 0, + "4": 0, + "5": 0, + "6": 0, + "7": 0, + "8": 0, + "9": 0, + "10": 0, + "11": 0, + "12": 0, + "13": 0, + "14": 0, + "15": 0, + "16": 0, + "17": 0, + "18": 0, + "19": 0, + "20": 0, + "21": 0, + "22": 0, + "23": 0, + "24": 0, + "25": 0, + "26": 0, + "27": 0, + "28": 0, + "29": 0, + "30": 0, + "31": 0, + "32": 0, + "33": 0, + "34": 0 + }, + "roi_mask": { + "0": [ + [ + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false + ] + ], + "1": [ + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false + ] + ], + "2": [ + [ + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + ], + "3": [ + [ + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false + ] + ], + "4": [ + [ + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false + ] + ], + "5": [ + [ + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false + ] + ], + "6": [ + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false + ] + ], + "7": [ + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false + ] + ], + "8": [ + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + ], + "9": [ + [ + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false + ] + ], + "10": [ + [ + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false + ] + ], + "11": [ + [ + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false + ] + ], + "12": [ + [ + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false + ] + ], + "13": [ + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false + ] + ], + "14": [ + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false + ] + ], + "15": [ + [ + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false + ] + ], + "16": [ + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false, + false + ] + ], + "17": [ + [ + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false + ] + ], + "18": [ + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + ], + "19": [ + [ + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ] + ], + "20": [ + [ + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false + ] + ], + "21": [ + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ] + ], + "22": [ + [ + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false, + false + ] + ], + "23": [ + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false + ] + ], + "24": [ + [ + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false + ] + ], + "25": [ + [ + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false + ] + ], + "26": [ + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ] + ], + "27": [ + [ + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ] + ], + "28": [ + [ + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false + ] + ], + "29": [ + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ] + ], + "30": [ + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false + ] + ], + "31": [ + [ + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + ], + "32": [ + [ + false, + false, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false + ] + ], + "33": [ + [ + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false + ] + ], + "34": [ + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false + ], + [ + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false + ], + [ + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false + ], + [ + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false + ], + [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false + ] + ] + } + } + } +} diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py index f8acc7b0c..a117217cc 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py @@ -7,8 +7,8 @@ .behavior_metadata.behavior_metadata import \ BehaviorMetadata from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.equipment_name import \ - EquipmentName + .behavior_metadata.equipment import \ + Equipment from allensdk.brain_observatory.behavior.session_apis.data_transforms import BehaviorOphysDataTransforms # noqa: E501 from allensdk.internal.brain_observatory.time_sync import OphysTimeAligner from allensdk.test.brain_observatory.behavior.data_objects.metadata\ @@ -452,8 +452,10 @@ def dummy_delay(self): xform_init) def dummy_get_metadata(self): - test_beh_meta = TestBehaviorMetadata().meta - test_beh_meta._equipment_name = EquipmentName( + test_beh_meta = TestBehaviorMetadata() + test_beh_meta.setup_class() + test_beh_meta = test_beh_meta.meta + test_beh_meta._equipment = Equipment( equipment_name=equipment_name) return test_beh_meta From 197a8ab9662241ad6142d441c5b268080ed33691 Mon Sep 17 00:00:00 2001 From: aamster Date: Fri, 25 Jun 2021 10:46:02 -0700 Subject: [PATCH 059/234] Adds from_internal test --- .../metadata/test_behavior_ophys_metadata.py | 66 ++++++++----------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py index bb7c98e60..f15c4a269 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py @@ -1,18 +1,13 @@ import json from pathlib import Path -from unittest.mock import create_autospec import pandas as pd import pynwb import pytest -from allensdk.brain_observatory.behavior.data_objects import BehaviorSessionId from allensdk.brain_observatory.behavior.data_objects.cell_specimen_table \ import \ CellSpecimenTable -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.behavior_metadata import \ - BehaviorMetadata from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.equipment import \ Equipment @@ -48,7 +43,8 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.ophys_session_id import \ OphysSessionId -from allensdk.internal.api import PostgresQueryMixin +from allensdk.core.auth_config import LIMS_DB_CREDENTIAL_MAP +from allensdk.internal.api import PostgresQueryMixin, db_connection_creator from allensdk.test.brain_observatory.behavior.data_objects.metadata \ .behavior_metadata.test_behavior_metadata import \ TestBehaviorMetadata @@ -113,43 +109,35 @@ def _get_mesoscope_meta(self): class TestInternal(TestBO): + @classmethod + def setup_method(self, method): + marks = getattr(method, 'pytestmark', None) + if marks: + marks = [m.name for m in marks] + + # Will only create a dbconn if the test requires_bamboo + if 'requires_bamboo' in marks: + self.dbconn = db_connection_creator( + fallback_credentials=LIMS_DB_CREDENTIAL_MAP) + + @pytest.mark.requires_bamboo @pytest.mark.parametrize('meso', [True, False]) - def test_from_internal(self, monkeypatch, meso): - mock_db_conn = create_autospec(PostgresQueryMixin, instance=True) - - behavior_session_id = self.meta.behavior_metadata.behavior_session_id - experiment_id = self.meta.ophys_metadata.ophys_experiment_id - - meta = self._get_mesoscope_meta() if meso else self.meta - - with monkeypatch.context() as m: - m.setattr(BehaviorSessionId, - 'from_lims', - lambda ophys_experiment_id, db: BehaviorSessionId( - behavior_session_id=behavior_session_id)) - m.setattr(BehaviorMetadata, - 'from_internal', - lambda behavior_session_id, lims_db: - meta.behavior_metadata) - if meso: - m.setattr(MesoscopeExperimentMetadata, - 'from_internal', - lambda ophys_experiment_id, lims_db: - meta.ophys_metadata) - else: - m.setattr(OphysExperimentMetadata, - 'from_internal', - lambda ophys_experiment_id, lims_db: - meta.ophys_metadata) - obt = BehaviorOphysMetadata.from_internal( - ophys_experiment_id=experiment_id, lims_db=mock_db_conn) + def test_from_internal(self, meso): + if meso: + ophys_experiment_id = 951980471 + else: + ophys_experiment_id = 994278291 + bom = BehaviorOphysMetadata.from_internal( + ophys_experiment_id=ophys_experiment_id, lims_db=self.dbconn) if meso: - assert isinstance(obt.ophys_metadata, MesoscopeExperimentMetadata) + assert isinstance(bom.ophys_metadata, + MesoscopeExperimentMetadata) else: - assert isinstance(obt.ophys_metadata, OphysExperimentMetadata) + assert isinstance(bom.ophys_metadata, OphysExperimentMetadata) - assert obt == meta + def test_foo(self): + pass class TestJson(TestBO): @@ -166,7 +154,7 @@ def setup_method(self, method): self.dict_repr = dict_repr @pytest.mark.parametrize('meso', [True, False]) - def test_from_json(self, monkeypatch, meso): + def test_from_json(self, meso): if meso: self.dict_repr['rig_name'] = 'MESO.1' bom = BehaviorOphysMetadata.from_json(dict_repr=self.dict_repr) From 24d0f07de1b736ac063d8d9c8bd4fa240f01cca2 Mon Sep 17 00:00:00 2001 From: aamster Date: Fri, 25 Jun 2021 11:41:54 -0700 Subject: [PATCH 060/234] linting --- .../behavior/behavior_session.py | 2 +- .../data_objects/base/readable_interfaces.py | 2 +- .../data_objects/base/writable_interfaces.py | 2 +- .../data_objects/cell_specimen_table.py | 12 +++--- .../behavior_session_uuid.py | 3 +- .../behavior_metadata/date_of_acquisition.py | 1 - .../metadata/behavior_metadata/foraging_id.py | 2 - .../imaging_plane_group.py | 2 +- .../mesoscope_experiment_metadata.py | 37 +++++++++---------- .../ophys_experiment_metadata.py | 1 - .../ophys_session_id.py | 2 +- .../subject_metadata/subject_metadata.py | 17 +++++---- .../session_apis/data_io/behavior_nwb_api.py | 12 +++--- .../data_io/behavior_ophys_nwb_api.py | 33 ++++++++--------- .../brain_observatory/comparison_utils.py | 2 +- .../metadata/test_behavior_ophys_metadata.py | 5 +-- .../behavior/test_behavior_lims_api.py | 5 --- .../test_behavior_ophys_data_xforms.py | 3 -- .../behavior/test_write_behavior_nwb.py | 4 -- .../behavior/test_write_nwb_behavior_ophys.py | 2 - 20 files changed, 62 insertions(+), 87 deletions(-) diff --git a/allensdk/brain_observatory/behavior/behavior_session.py b/allensdk/brain_observatory/behavior/behavior_session.py index a803da08d..44f764253 100644 --- a/allensdk/brain_observatory/behavior/behavior_session.py +++ b/allensdk/brain_observatory/behavior/behavior_session.py @@ -20,7 +20,7 @@ from allensdk.core.lazy_property import LazyPropertyMixin from allensdk.brain_observatory.session_api_utils import ParamsMixin from allensdk.brain_observatory.behavior.session_apis.data_io import ( - BehaviorNwbApi, BehaviorJsonApi, BehaviorLimsApi) + BehaviorJsonApi, BehaviorLimsApi) from allensdk.brain_observatory.behavior.session_apis.abcs.\ session_base.behavior_base import BehaviorBase from allensdk.brain_observatory.behavior.trials_processing import ( diff --git a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces.py index 237eaf6b2..409945a83 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces.py @@ -103,4 +103,4 @@ def from_sync_file(cls, *args) -> "DataObject": DataObject: An instantiated DataObject which has `name` and `value` properties """ - raise NotImplementedError() \ No newline at end of file + raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces.py b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces.py index 45d6319b3..37c015947 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces.py @@ -37,4 +37,4 @@ def to_nwb(self, nwbfile: NWBFile, *args) -> NWBFile: # pragma: no cover An NWB file object that has had data from the DataObject added to it. """ - raise NotImplementedError() \ No newline at end of file + raise NotImplementedError() diff --git a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py index 239fba7ea..5b8847c10 100644 --- a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py +++ b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py @@ -8,13 +8,13 @@ from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ JsonReadableInterface, LimsReadableInterface, NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ +from allensdk.brain_observatory.behavior.data_objects.base \ .writable_interfaces import \ NwbWritableInterface -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .behavior_metadata.equipment import \ EquipmentType -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .behavior_ophys_metadata import \ BehaviorOphysMetadata from allensdk.brain_observatory.behavior.data_objects.metadata \ @@ -130,9 +130,9 @@ def to_nwb(self, nwbfile: NWBFile, meta: BehaviorOphysMetadata) -> NWBFile: fov_height = metadata.field_of_view_height imaging_plane_description = "{} field of view in {} at depth {} " \ "um".format( - (fov_width, fov_height), - imaging_plane_meta.targeted_structure, - metadata.imaging_depth) + (fov_width, fov_height), + imaging_plane_meta.targeted_structure, + metadata.imaging_depth) # Optical Channel: optical_channel = OpticalChannel( diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py index 4c2726354..0129e8d10 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_session_uuid.py @@ -14,7 +14,8 @@ class BehaviorSessionUUID(DataObject, StimulusFileReadableInterface, NwbReadableInterface): """the universally unique identifier (UUID)""" def __init__(self, behavior_session_uuid: Optional[uuid.UUID]): - super().__init__(name="behavior_session_uuid", value=behavior_session_uuid) + super().__init__(name="behavior_session_uuid", + value=behavior_session_uuid) @classmethod def from_stimulus_file( diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py index 4ec85e303..a3ee631dc 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py @@ -91,4 +91,3 @@ def validate(self, stimulus_file: StimulusFile, @staticmethod def to_utc(date_of_acquisition: datetime): return pytz.utc.localize(dt=date_of_acquisition) - diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py index 004b51237..3466f1a4a 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py @@ -1,7 +1,5 @@ import uuid -from pynwb import NWBFile - from allensdk.brain_observatory.behavior.data_objects import DataObject from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/imaging_plane_group.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/imaging_plane_group.py index a151f14ea..c8e75f3db 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/imaging_plane_group.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/imaging_plane_group.py @@ -32,7 +32,7 @@ def from_lims(cls, ophys_experiment_id: int, JOIN ophys_imaging_plane_groups pg ON pg.id = oe.ophys_imaging_plane_group_id WHERE os.id = ( - SELECT oe.ophys_session_id + SELECT oe.ophys_session_id FROM ophys_experiments oe WHERE oe.id = {ophys_experiment_id} ) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py index 2e4d182c6..c57755e57 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py @@ -1,31 +1,31 @@ from pynwb import NWBFile -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.imaging_plane import \ - ImagingPlane -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.ophys_experiment_metadata import \ - OphysExperimentMetadata -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .ophys_experiment_metadata.emission_lambda import \ EmissionLambda -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .ophys_experiment_metadata.experiment_container_id import \ ExperimentContainerId -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .ophys_experiment_metadata.field_of_view_shape import \ FieldOfViewShape -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .ophys_experiment_metadata.imaging_depth import \ ImagingDepth -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.mesoscope_experiment_metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ + .ophys_experiment_metadata.imaging_plane import \ + ImagingPlane +from allensdk.brain_observatory.behavior.data_objects.metadata \ + .ophys_experiment_metadata.mesoscope_experiment_metadata \ .imaging_plane_group import \ ImagingPlaneGroup -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ + .ophys_experiment_metadata.ophys_experiment_metadata import \ + OphysExperimentMetadata +from allensdk.brain_observatory.behavior.data_objects.metadata \ .ophys_experiment_metadata.ophys_session_id import \ OphysSessionId -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .ophys_experiment_metadata.project_code import \ ProjectCode from allensdk.internal.api import PostgresQueryMixin @@ -65,8 +65,7 @@ def from_internal( return cls( ophys_experiment_id=ophys_experiment_metadata.ophys_experiment_id, ophys_session_id=ophys_experiment_metadata._ophys_session_id, - experiment_container_id= - ophys_experiment_metadata._experiment_container_id, + experiment_container_id=ophys_experiment_metadata._experiment_container_id, # noqa E501 emission_lambda=ophys_experiment_metadata._emission_lambda, imaging_plane=ophys_experiment_metadata._imaging_plane, field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, @@ -82,8 +81,7 @@ def from_json(cls, dict_repr: dict) -> "MesoscopeExperimentMetadata": return cls( ophys_experiment_id=ophys_experiment_metadata.ophys_experiment_id, ophys_session_id=ophys_experiment_metadata._ophys_session_id, - experiment_container_id= - ophys_experiment_metadata._experiment_container_id, + experiment_container_id=ophys_experiment_metadata._experiment_container_id, # noqa E501 emission_lambda=ophys_experiment_metadata._emission_lambda, imaging_plane=ophys_experiment_metadata._imaging_plane, field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, @@ -99,8 +97,7 @@ def from_nwb(cls, nwbfile: NWBFile) -> "MesoscopeExperimentMetadata": return cls( ophys_experiment_id=ophys_experiment_metadata.ophys_experiment_id, ophys_session_id=ophys_experiment_metadata._ophys_session_id, - experiment_container_id= - ophys_experiment_metadata._experiment_container_id, + experiment_container_id=ophys_experiment_metadata._experiment_container_id, # noqa E501 emission_lambda=ophys_experiment_metadata._emission_lambda, imaging_plane=ophys_experiment_metadata._imaging_plane, field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py index 1e835f2fa..065d1e2dd 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py @@ -1,4 +1,3 @@ -import warnings from typing import Optional from pynwb import NWBFile diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_session_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_session_id.py index ea5a8e33a..f70ea8574 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_session_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_session_id.py @@ -8,7 +8,7 @@ class OphysSessionId(DataObject, LimsReadableInterface, - JsonReadableInterface, NwbReadableInterface): + JsonReadableInterface, NwbReadableInterface): """"Ophys session id""" def __init__(self, session_id: int): super().__init__(name='session_id', diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py index 6aa531e6a..6fadf6f14 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py @@ -10,22 +10,22 @@ from allensdk.brain_observatory.behavior.data_objects.base \ .writable_interfaces import \ JsonWritableInterface, NwbWritableInterface -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.age import \ Age -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.driver_line import \ DriverLine -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.full_genotype import \ FullGenotype -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.mouse_id import \ MouseId -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.reporter_line import \ ReporterLine -from allensdk.brain_observatory.behavior.data_objects.metadata\ +from allensdk.brain_observatory.behavior.data_objects.metadata \ .subject_metadata.sex import \ Sex from allensdk.brain_observatory.behavior.schemas import SubjectMetadataSchema @@ -37,6 +37,7 @@ class SubjectMetadata(DataObject, LimsReadableInterface, NwbReadableInterface, NwbWritableInterface, JsonReadableInterface, JsonWritableInterface): """Subject metadata""" + def __init__(self, sex: Sex, age: Age, @@ -68,7 +69,7 @@ def from_lims(cls, behavior_session_id=behavior_session_id.value, lims_db=lims_db) mouse_id = MouseId.from_lims( behavior_session_id=behavior_session_id.value, - lims_db=lims_db) + lims_db=lims_db) return cls( sex=sex, age=age, @@ -162,4 +163,4 @@ def driver_line(self) -> List[str]: @property def mouse_id(self) -> int: - return self._mouse_id.value \ No newline at end of file + return self._mouse_id.value diff --git a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py index 0548abe1e..73b8fa2c1 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_nwb_api.py @@ -5,18 +5,16 @@ import numpy as np import pandas as pd import pytz - from pynwb import NWBHDF5IO, NWBFile import allensdk.brain_observatory.nwb as nwb -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.behavior_metadata import ( - get_expt_description, BehaviorMetadata -) -from allensdk.brain_observatory.behavior.session_apis.abcs.\ - session_base.behavior_base import BehaviorBase +from allensdk.brain_observatory.behavior.data_objects.metadata \ + .behavior_metadata.behavior_metadata import get_expt_description, \ + BehaviorMetadata from allensdk.brain_observatory.behavior.schemas import ( BehaviorTaskParametersSchema, OphysBehaviorMetadataSchema) +from allensdk.brain_observatory.behavior.session_apis.abcs. \ + session_base.behavior_base import BehaviorBase from allensdk.brain_observatory.behavior.stimulus_processing import \ StimulusTemplate, StimulusTemplateFactory, is_change_event from allensdk.brain_observatory.behavior.trials_processing import ( diff --git a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py index e2de4e597..45ee9dc3b 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_ophys_nwb_api.py @@ -2,45 +2,42 @@ import warnings from typing import Optional +import SimpleITK as sitk import numpy as np import pandas as pd import pynwb import pytz -import SimpleITK as sitk from hdmf.backends.hdf5 import H5DataIO - from pynwb import NWBHDF5IO, NWBFile -from allensdk.brain_observatory.behavior.data_objects.metadata\ +import allensdk.brain_observatory.nwb as nwb +from allensdk.brain_observatory.behavior.data_objects.metadata \ + .behavior_metadata.behavior_metadata import get_expt_description +from allensdk.brain_observatory.behavior.data_objects.metadata \ .ophys_experiment_metadata.ophys_experiment_metadata \ import OphysExperimentMetadata from allensdk.brain_observatory.behavior.event_detection import \ filter_events_array -import allensdk.brain_observatory.nwb as nwb -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.behavior_metadata import ( - get_expt_description +from allensdk.brain_observatory.behavior.eye_tracking_processing import ( + determine_outliers, determine_likely_blinks ) -from allensdk.brain_observatory.behavior.session_apis.abcs.session_base. \ - behavior_ophys_base import BehaviorOphysBase from allensdk.brain_observatory.behavior.schemas import ( BehaviorTaskParametersSchema, OphysEyeTrackingRigMetadataSchema) +from allensdk.brain_observatory.behavior.session_apis.abcs.session_base. \ + behavior_ophys_base import BehaviorOphysBase +from allensdk.brain_observatory.behavior.session_apis.data_io import ( + BehaviorNwbApi +) from allensdk.brain_observatory.behavior.trials_processing import ( TRIAL_COLUMN_DESCRIPTION_DICT ) -from allensdk.brain_observatory.nwb import TimeSeries -from allensdk.brain_observatory.nwb.eye_tracking.ndx_ellipse_eye_tracking import ( # noqa: E501 - EllipseEyeTracking, EllipseSeries) from allensdk.brain_observatory.behavior.write_nwb.extensions \ .event_detection.ndx_ophys_events import OphysEventDetection +from allensdk.brain_observatory.nwb import TimeSeries +from allensdk.brain_observatory.nwb.eye_tracking.ndx_ellipse_eye_tracking \ + import EllipseEyeTracking, EllipseSeries from allensdk.brain_observatory.nwb.metadata import load_pynwb_extension -from allensdk.brain_observatory.behavior.session_apis.data_io import ( - BehaviorNwbApi -) from allensdk.brain_observatory.nwb.nwb_utils import set_omitted_stop_time -from allensdk.brain_observatory.behavior.eye_tracking_processing import ( - determine_outliers, determine_likely_blinks -) load_pynwb_extension(BehaviorTaskParametersSchema, 'ndx-aibs-behavior-ophys') diff --git a/allensdk/brain_observatory/comparison_utils.py b/allensdk/brain_observatory/comparison_utils.py index 8f61ab231..4fbbc9f89 100644 --- a/allensdk/brain_observatory/comparison_utils.py +++ b/allensdk/brain_observatory/comparison_utils.py @@ -65,4 +65,4 @@ def compare_fields(x1: Any, x2: Any, err_msg="", key_err_msg = f"Mismatch when checking key {key}. {err_msg}" compare_fields(x1[key], x2[key], err_msg=key_err_msg) else: - assert x1 == x2, err_msg \ No newline at end of file + assert x1 == x2, err_msg diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py index f15c4a269..3ace40a77 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py @@ -44,7 +44,7 @@ .ophys_experiment_metadata.ophys_session_id import \ OphysSessionId from allensdk.core.auth_config import LIMS_DB_CREDENTIAL_MAP -from allensdk.internal.api import PostgresQueryMixin, db_connection_creator +from allensdk.internal.api import db_connection_creator from allensdk.test.brain_observatory.behavior.data_objects.metadata \ .behavior_metadata.test_behavior_metadata import \ TestBehaviorMetadata @@ -93,8 +93,7 @@ def _get_mesoscope_meta(self): meso_meta = MesoscopeExperimentMetadata( ophys_experiment_id=ophys_experiment_metadata.ophys_experiment_id, ophys_session_id=ophys_experiment_metadata._ophys_session_id, - experiment_container_id= - ophys_experiment_metadata._experiment_container_id, + experiment_container_id=ophys_experiment_metadata._experiment_container_id, # noqa E501 emission_lambda=ophys_experiment_metadata._emission_lambda, imaging_plane=ophys_experiment_metadata._imaging_plane, field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py b/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py index a64d8ae21..4705513af 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_lims_api.py @@ -1,9 +1,7 @@ -import json import math import pickle import tempfile from datetime import datetime -from pathlib import Path from uuid import UUID import numpy as np @@ -14,9 +12,6 @@ from allensdk import OneResultExpectedError from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import StimulusTimestamps -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.behavior_metadata import \ - BehaviorMetadata from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_session_uuid import \ BehaviorSessionUUID diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py index a117217cc..808501974 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_data_xforms.py @@ -3,9 +3,6 @@ import numpy as np import pandas as pd -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.behavior_metadata import \ - BehaviorMetadata from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.equipment import \ Equipment diff --git a/allensdk/test/brain_observatory/behavior/test_write_behavior_nwb.py b/allensdk/test/brain_observatory/behavior/test_write_behavior_nwb.py index 475fc90d1..fe3f585f2 100644 --- a/allensdk/test/brain_observatory/behavior/test_write_behavior_nwb.py +++ b/allensdk/test/brain_observatory/behavior/test_write_behavior_nwb.py @@ -4,13 +4,9 @@ import numpy as np import pandas as pd -import pynwb import pytest import allensdk.brain_observatory.nwb as nwb -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .behavior_metadata.behavior_metadata import \ - BehaviorMetadata from allensdk.brain_observatory.behavior.session_apis.data_io import ( BehaviorNwbApi) from allensdk.brain_observatory.behavior.stimulus_processing import \ diff --git a/allensdk/test/brain_observatory/behavior/test_write_nwb_behavior_ophys.py b/allensdk/test/brain_observatory/behavior/test_write_nwb_behavior_ophys.py index 233fead81..2d9621a37 100644 --- a/allensdk/test/brain_observatory/behavior/test_write_nwb_behavior_ophys.py +++ b/allensdk/test/brain_observatory/behavior/test_write_nwb_behavior_ophys.py @@ -1,11 +1,9 @@ import math import mock from pathlib import Path -import warnings import numpy as np import pandas as pd -import pynwb import pytest import allensdk.brain_observatory.nwb as nwb From 5b126853ed33acde8b7228165982404c33230f62 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 29 Jun 2021 08:26:04 -0700 Subject: [PATCH 061/234] Moves emission lambda, imaging plane meta to CellSpecimenTable --- .../data_objects/cell_specimen_table.py | 90 ++++++++++++++----- .../emission_lambda.py | 21 ----- .../mesoscope_experiment_metadata.py | 13 --- .../ophys_experiment_metadata.py | 37 -------- .../brain_observatory/behavior/conftest.py | 4 - .../metadata/test_behavior_ophys_metadata.py | 29 ------ 6 files changed, 67 insertions(+), 127 deletions(-) delete mode 100644 allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/emission_lambda.py diff --git a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py index 5b8847c10..c2a8130b7 100644 --- a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py +++ b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py @@ -20,15 +20,35 @@ from allensdk.brain_observatory.behavior.data_objects.metadata \ .ophys_experiment_metadata.field_of_view_shape import \ FieldOfViewShape +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.imaging_plane import \ + ImagingPlane from allensdk.brain_observatory.nwb import CELL_SPECIMEN_COL_DESCRIPTIONS from allensdk.internal.api import PostgresQueryMixin +class CellSpecimenTableMeta: + def __init__(self, imaging_plane: ImagingPlane, emission_lambda=520.0): + self._emission_lambda = emission_lambda + self._imaging_plane = imaging_plane + + @property + def emission_lambda(self): + return self._emission_lambda + + @property + def imaging_plane(self): + return self._imaging_plane + + class CellSpecimenTable(DataObject, LimsReadableInterface, JsonReadableInterface, NwbReadableInterface, NwbWritableInterface): - def __init__(self, cell_specimen_table: pd.DataFrame): + def __init__(self, cell_specimen_table: pd.DataFrame, + meta: CellSpecimenTableMeta): super().__init__(name='cell_specimen_table', value=cell_specimen_table) + self._meta = meta + @classmethod def from_lims(cls, ophys_experiment_id: int, @@ -63,7 +83,11 @@ def get_ophys_cell_segmentation_run_id() -> int: ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) cell_specimen_table = cls._postprocess( cell_specimen_table=cell_specimen_table, fov_shape=fov_shape) - return cls(cell_specimen_table=cell_specimen_table) + + imaging_plane_meta = ImagingPlane.from_internal( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + meta = CellSpecimenTableMeta(imaging_plane=imaging_plane_meta) + return cls(cell_specimen_table=cell_specimen_table, meta=meta) @classmethod def from_json(cls, dict_repr: dict) -> "CellSpecimenTable": @@ -71,30 +95,51 @@ def from_json(cls, dict_repr: dict) -> "CellSpecimenTable": fov_shape = FieldOfViewShape.from_json(dict_repr=dict_repr) cell_specimen_table = cls._postprocess( cell_specimen_table=cell_specimen_table, fov_shape=fov_shape) - return cls(cell_specimen_table=cell_specimen_table) + + imaging_plane_meta = ImagingPlane.from_json(dict_repr=dict_repr) + meta = CellSpecimenTableMeta(imaging_plane=imaging_plane_meta) + return cls(cell_specimen_table=cell_specimen_table, meta=meta) @classmethod def from_nwb(cls, nwbfile: NWBFile, filter_invalid_rois=False) -> "CellSpecimenTable": # NOTE: ROI masks are stored in full frame width and height arrays - df = nwbfile.processing[ - 'ophys'].data_interfaces[ - 'image_segmentation'].plane_segmentations[ - 'cell_specimen_table'].to_dataframe() + ophys_module = nwbfile.processing['ophys'] + image_seg = ophys_module.data_interfaces['image_segmentation'] + plane_segmentations = image_seg.plane_segmentations + cell_specimen_table = plane_segmentations['cell_specimen_table'] + + def _read_table(cell_specimen_table): + df = cell_specimen_table.to_dataframe() + + # Because pynwb stores this field as "image_mask", it is renamed + # here + df = df.rename(columns={'image_mask': 'roi_mask'}) + + df.index.rename('cell_roi_id', inplace=True) + df['cell_specimen_id'] = [None if csid == -1 else csid + for csid in df['cell_specimen_id'].values] + + df.reset_index(inplace=True) + df.set_index('cell_specimen_id', inplace=True) + + if filter_invalid_rois: + df = df[df["valid_roi"]] + return df - # Because pynwb stores this field as "image_mask", it is renamed here - df = df.rename(columns={'image_mask': 'roi_mask'}) + def _read_meta(cell_specimen_table) -> CellSpecimenTableMeta: + imaging_plane = cell_specimen_table.imaging_plane + optical_channel = imaging_plane.optical_channel[0] + emission_lambda = optical_channel.emission_lambda - df.index.rename('cell_roi_id', inplace=True) - df['cell_specimen_id'] = [None if csid == -1 else csid - for csid in df['cell_specimen_id'].values] + imaging_plane = ImagingPlane.from_nwb(nwbfile=nwbfile) + return CellSpecimenTableMeta(emission_lambda=emission_lambda, + imaging_plane=imaging_plane) - df.reset_index(inplace=True) - df.set_index('cell_specimen_id', inplace=True) + df = _read_table(cell_specimen_table=cell_specimen_table) + meta = _read_meta(cell_specimen_table=cell_specimen_table) - if filter_invalid_rois: - df = df[df["valid_roi"]] - return cls(cell_specimen_table=df) + return cls(cell_specimen_table=df, meta=meta) def to_nwb(self, nwbfile: NWBFile, meta: BehaviorOphysMetadata) -> NWBFile: """ @@ -107,7 +152,6 @@ def to_nwb(self, nwbfile: NWBFile, meta: BehaviorOphysMetadata) -> NWBFile: cell_roi_table = self.value.reset_index().set_index( 'cell_roi_id') metadata = nwbfile.lab_meta_data['metadata'] - imaging_plane_meta = meta.ophys_metadata.imaging_plane # Device: equipment = meta.behavior_metadata.equipment @@ -131,14 +175,14 @@ def to_nwb(self, nwbfile: NWBFile, meta: BehaviorOphysMetadata) -> NWBFile: imaging_plane_description = "{} field of view in {} at depth {} " \ "um".format( (fov_width, fov_height), - imaging_plane_meta.targeted_structure, + self._meta.imaging_plane.targeted_structure, # noqa E501 metadata.imaging_depth) # Optical Channel: optical_channel = OpticalChannel( name='channel_1', description='2P Optical Channel', - emission_lambda=meta.ophys_metadata.emission_lambda) + emission_lambda=self._meta.emission_lambda) # Imaging Plane: imaging_plane = nwbfile.create_imaging_plane( @@ -146,10 +190,10 @@ def to_nwb(self, nwbfile: NWBFile, meta: BehaviorOphysMetadata) -> NWBFile: optical_channel=optical_channel, description=imaging_plane_description, device=device, - excitation_lambda=imaging_plane_meta.excitation_lambda, - imaging_rate=imaging_plane_meta.ophys_frame_rate, + excitation_lambda=self._meta.imaging_plane.excitation_lambda, + imaging_rate=self._meta.imaging_plane.ophys_frame_rate, indicator=meta.behavior_metadata.subject_metadata.indicator, - location=imaging_plane_meta.targeted_structure) + location=self._meta.imaging_plane.targeted_structure) # Image Segmentation: image_segmentation = ImageSegmentation(name="image_segmentation") diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/emission_lambda.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/emission_lambda.py deleted file mode 100644 index 3b1142698..000000000 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/emission_lambda.py +++ /dev/null @@ -1,21 +0,0 @@ -from pynwb import NWBFile - -from allensdk.brain_observatory.behavior.data_objects import DataObject -from allensdk.brain_observatory.behavior.data_objects.base\ - .readable_interfaces import \ - NwbReadableInterface - - -class EmissionLambda(DataObject, NwbReadableInterface): - def __init__(self, emission_lambda=520.0): - super().__init__(name='emission_lambda', value=emission_lambda) - - @classmethod - def from_nwb(cls, nwbfile: NWBFile) -> "EmissionLambda": - ophys_module = nwbfile.processing['ophys'] - image_seg = ophys_module.data_interfaces['image_segmentation'] - imaging_plane = image_seg.plane_segmentations[ - 'cell_specimen_table'].imaging_plane - optical_channel = imaging_plane.optical_channel[0] - emission_lambda = optical_channel.emission_lambda - return cls(emission_lambda=emission_lambda) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py index c57755e57..35dadf770 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py @@ -1,8 +1,5 @@ from pynwb import NWBFile -from allensdk.brain_observatory.behavior.data_objects.metadata \ - .ophys_experiment_metadata.emission_lambda import \ - EmissionLambda from allensdk.brain_observatory.behavior.data_objects.metadata \ .ophys_experiment_metadata.experiment_container_id import \ ExperimentContainerId @@ -36,8 +33,6 @@ def __init__(self, ophys_experiment_id: int, ophys_session_id: OphysSessionId, experiment_container_id: ExperimentContainerId, - emission_lambda: EmissionLambda, - imaging_plane: ImagingPlane, field_of_view_shape: FieldOfViewShape, imaging_depth: ImagingDepth, imaging_plane_group: ImagingPlaneGroup, @@ -46,8 +41,6 @@ def __init__(self, ophys_experiment_id=ophys_experiment_id, ophys_session_id=ophys_session_id, experiment_container_id=experiment_container_id, - emission_lambda=emission_lambda, - imaging_plane=imaging_plane, field_of_view_shape=field_of_view_shape, imaging_depth=imaging_depth, project_code=project_code @@ -66,8 +59,6 @@ def from_internal( ophys_experiment_id=ophys_experiment_metadata.ophys_experiment_id, ophys_session_id=ophys_experiment_metadata._ophys_session_id, experiment_container_id=ophys_experiment_metadata._experiment_container_id, # noqa E501 - emission_lambda=ophys_experiment_metadata._emission_lambda, - imaging_plane=ophys_experiment_metadata._imaging_plane, field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, imaging_depth=ophys_experiment_metadata._imaging_depth, project_code=ophys_experiment_metadata._project_code, @@ -82,8 +73,6 @@ def from_json(cls, dict_repr: dict) -> "MesoscopeExperimentMetadata": ophys_experiment_id=ophys_experiment_metadata.ophys_experiment_id, ophys_session_id=ophys_experiment_metadata._ophys_session_id, experiment_container_id=ophys_experiment_metadata._experiment_container_id, # noqa E501 - emission_lambda=ophys_experiment_metadata._emission_lambda, - imaging_plane=ophys_experiment_metadata._imaging_plane, field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, imaging_depth=ophys_experiment_metadata._imaging_depth, project_code=ophys_experiment_metadata._project_code, @@ -98,8 +87,6 @@ def from_nwb(cls, nwbfile: NWBFile) -> "MesoscopeExperimentMetadata": ophys_experiment_id=ophys_experiment_metadata.ophys_experiment_id, ophys_session_id=ophys_experiment_metadata._ophys_session_id, experiment_container_id=ophys_experiment_metadata._experiment_container_id, # noqa E501 - emission_lambda=ophys_experiment_metadata._emission_lambda, - imaging_plane=ophys_experiment_metadata._imaging_plane, field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, imaging_depth=ophys_experiment_metadata._imaging_depth, project_code=ophys_experiment_metadata._project_code, diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py index 065d1e2dd..4c0624049 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/ophys_experiment_metadata.py @@ -6,9 +6,6 @@ from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ InternalReadableInterface, JsonReadableInterface, NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.emission_lambda import \ - EmissionLambda from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.experiment_container_id import \ ExperimentContainerId @@ -18,9 +15,6 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.imaging_depth import \ ImagingDepth -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.imaging_plane import \ - ImagingPlane from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.ophys_session_id import \ OphysSessionId @@ -37,8 +31,6 @@ def __init__(self, ophys_experiment_id: int, ophys_session_id: OphysSessionId, experiment_container_id: ExperimentContainerId, - imaging_plane: ImagingPlane, - emission_lambda: EmissionLambda, field_of_view_shape: FieldOfViewShape, imaging_depth: ImagingDepth, project_code: Optional[ProjectCode] = None): @@ -46,8 +38,6 @@ def __init__(self, self._ophys_experiment_id = ophys_experiment_id self._ophys_session_id = ophys_session_id self._experiment_container_id = experiment_container_id - self._imaging_plane = imaging_plane - self._emission_lambda = emission_lambda self._field_of_view_shape = field_of_view_shape self._imaging_depth = imaging_depth self._project_code = project_code @@ -64,9 +54,6 @@ def from_internal( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) experiment_container_id = ExperimentContainerId.from_lims( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) - imaging_plane = ImagingPlane.from_internal( - ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) - emission_lambda = EmissionLambda(emission_lambda=520.0) field_of_view_shape = FieldOfViewShape.from_lims( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) imaging_depth = ImagingDepth.from_lims( @@ -77,8 +64,6 @@ def from_internal( return cls( ophys_experiment_id=ophys_experiment_id, ophys_session_id=ophys_session_id, - emission_lambda=emission_lambda, - imaging_plane=imaging_plane, experiment_container_id=experiment_container_id, field_of_view_shape=field_of_view_shape, imaging_depth=imaging_depth, @@ -91,54 +76,32 @@ def from_json(cls, dict_repr: dict) -> "OphysExperimentMetadata": experiment_container_id = ExperimentContainerId.from_json( dict_repr=dict_repr) ophys_experiment_id = dict_repr['ophys_experiment_id'] - imaging_plane = ImagingPlane.from_json(dict_repr=dict_repr) - emission_lambda = EmissionLambda() field_of_view_shape = FieldOfViewShape.from_json(dict_repr=dict_repr) imaging_depth = ImagingDepth.from_json(dict_repr=dict_repr) return OphysExperimentMetadata( ophys_experiment_id=ophys_experiment_id, ophys_session_id=ophys_session_id, experiment_container_id=experiment_container_id, - imaging_plane=imaging_plane, - emission_lambda=emission_lambda, field_of_view_shape=field_of_view_shape, imaging_depth=imaging_depth ) @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "OphysExperimentMetadata": - if 'ophys' not in nwbfile.processing: - raise RuntimeError('Key "ophys" not found in nwb file ' - '(needed to read imaging plane metadata). ' - 'Did you forget to write cell specimen table ' - 'to nwb?') - ophys_experiment_id = int(nwbfile.identifier) ophys_session_id = OphysSessionId.from_nwb(nwbfile=nwbfile) experiment_container_id = ExperimentContainerId.from_nwb( nwbfile=nwbfile) - imaging_plane = ImagingPlane.from_nwb(nwbfile=nwbfile) - emission_lambda = EmissionLambda.from_nwb(nwbfile=nwbfile) field_of_view_shape = FieldOfViewShape.from_nwb(nwbfile=nwbfile) imaging_depth = ImagingDepth.from_nwb(nwbfile=nwbfile) return OphysExperimentMetadata( ophys_experiment_id=ophys_experiment_id, ophys_session_id=ophys_session_id, experiment_container_id=experiment_container_id, - imaging_plane=imaging_plane, - emission_lambda=emission_lambda, field_of_view_shape=field_of_view_shape, imaging_depth=imaging_depth ) - @property - def emission_lambda(self) -> float: - return self._emission_lambda.value - - @property - def imaging_plane(self) -> ImagingPlane: - return self._imaging_plane - # TODO rename to ophys_container_id @property def experiment_container_id(self) -> int: diff --git a/allensdk/test/brain_observatory/behavior/conftest.py b/allensdk/test/brain_observatory/behavior/conftest.py index 74e5d2c1f..6f01452f3 100644 --- a/allensdk/test/brain_observatory/behavior/conftest.py +++ b/allensdk/test/brain_observatory/behavior/conftest.py @@ -30,9 +30,6 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_ophys_metadata import \ BehaviorOphysMetadata -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.emission_lambda import \ - EmissionLambda from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.experiment_container_id import \ ExperimentContainerId @@ -281,7 +278,6 @@ def behavior_ophys_metadata_fixture( targeted_structure='VISp', excitation_lambda=1.0 ), - emission_lambda=EmissionLambda(emission_lambda=1.0), field_of_view_shape=FieldOfViewShape(width=4, height=4), imaging_depth=ImagingDepth(imaging_depth=375) ) diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py index 3ace40a77..3601ee128 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py @@ -14,9 +14,6 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_ophys_metadata import \ BehaviorOphysMetadata -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.emission_lambda import \ - EmissionLambda from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.experiment_container_id import \ ExperimentContainerId @@ -65,12 +62,6 @@ def _get_meta(): ophys_session_id=OphysSessionId(session_id=999), experiment_container_id=ExperimentContainerId( experiment_container_id=5678), - imaging_plane=ImagingPlane( - ophys_frame_rate=31.0, - targeted_structure='VISp', - excitation_lambda=1.0 - ), - emission_lambda=EmissionLambda(emission_lambda=1.0), field_of_view_shape=FieldOfViewShape(width=4, height=4), imaging_depth=ImagingDepth(imaging_depth=375) ) @@ -94,8 +85,6 @@ def _get_mesoscope_meta(self): ophys_experiment_id=ophys_experiment_metadata.ophys_experiment_id, ophys_session_id=ophys_experiment_metadata._ophys_session_id, experiment_container_id=ophys_experiment_metadata._experiment_container_id, # noqa E501 - emission_lambda=ophys_experiment_metadata._emission_lambda, - imaging_plane=ophys_experiment_metadata._imaging_plane, field_of_view_shape=ophys_experiment_metadata._field_of_view_shape, imaging_depth=ophys_experiment_metadata._imaging_depth, project_code=ophys_experiment_metadata._project_code, @@ -173,19 +162,6 @@ def setup_method(self, method): session_start_time=self.meta.behavior_metadata.date_of_acquisition ) - @pytest.mark.parametrize('roundtrip', [True, False]) - def test_write_nwb_read_no_cell_specimen_table( - self, roundtrip, data_object_roundtrip_fixture): - self.meta.to_nwb(nwbfile=self.nwbfile) - - with pytest.raises(RuntimeError): - if roundtrip: - data_object_roundtrip_fixture( - nwbfile=self.nwbfile, - data_object_cls=BehaviorOphysMetadata) - else: - self.meta.from_nwb(nwbfile=self.nwbfile) - @pytest.mark.parametrize('meso', [True, False]) @pytest.mark.parametrize('roundtrip', [True, False]) def test_read_write_nwb(self, roundtrip, cell_specimen_table, @@ -195,11 +171,6 @@ def test_read_write_nwb(self, roundtrip, cell_specimen_table, self.meta.to_nwb(nwbfile=self.nwbfile) - cell_specimen_table = pd.DataFrame(cell_specimen_table) - cell_specimen_table = CellSpecimenTable( - cell_specimen_table=cell_specimen_table) - cell_specimen_table.to_nwb(nwbfile=self.nwbfile, meta=self.meta) - if roundtrip: obt = data_object_roundtrip_fixture( nwbfile=self.nwbfile, From 4b7c7f125e03e4761f749208861585a8e4381647 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 29 Jun 2021 09:38:30 -0700 Subject: [PATCH 062/234] remove reliance on metadata in cell specimen table --- .../data_objects/base/writable_interfaces.py | 2 +- .../data_objects/cell_specimen_table.py | 20 ++--------- .../behavior_metadata/behavior_metadata.py | 2 +- .../metadata/behavior_metadata/equipment.py | 23 +++++++++++-- .../imaging_plane.py | 34 ++++++++++++++++--- 5 files changed, 54 insertions(+), 27 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces.py b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces.py index 37c015947..04d04fef9 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/writable_interfaces.py @@ -22,7 +22,7 @@ def to_json(self) -> dict: # pragma: no cover class NwbWritableInterface(abc.ABC): """Marks a data object as writable to NWB""" @abc.abstractmethod - def to_nwb(self, nwbfile: NWBFile, *args) -> NWBFile: # pragma: no cover + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: # pragma: no cover """Given an already populated DataObject, return an pyNWB file object that had had DataObject data added. diff --git a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py index c2a8130b7..74fd021de 100644 --- a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py +++ b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py @@ -141,7 +141,7 @@ def _read_meta(cell_specimen_table) -> CellSpecimenTableMeta: return cls(cell_specimen_table=df, meta=meta) - def to_nwb(self, nwbfile: NWBFile, meta: BehaviorOphysMetadata) -> NWBFile: + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: """ :param nwbfile In-memory nwb file object @@ -153,21 +153,7 @@ def to_nwb(self, nwbfile: NWBFile, meta: BehaviorOphysMetadata) -> NWBFile: 'cell_roi_id') metadata = nwbfile.lab_meta_data['metadata'] - # Device: - equipment = meta.behavior_metadata.equipment - if equipment.type == EquipmentType.MESOSCOPE: - device_config = { - "name": equipment.value, - "description": "Allen Brain Observatory - Mesoscope 2P Rig" - } - else: - device_config = { - "name": equipment.value, - "description": "Allen Brain Observatory - Scientifica 2P Rig", - "manufacturer": "Scientifica" - } - nwbfile.create_device(**device_config) - device = nwbfile.get_device(equipment.value) + device = nwbfile.get_device() # FOV: fov_width = metadata.field_of_view_width @@ -192,7 +178,7 @@ def to_nwb(self, nwbfile: NWBFile, meta: BehaviorOphysMetadata) -> NWBFile: device=device, excitation_lambda=self._meta.imaging_plane.excitation_lambda, imaging_rate=self._meta.imaging_plane.ophys_frame_rate, - indicator=meta.behavior_metadata.subject_metadata.indicator, + indicator=self._meta.imaging_plane.indicator, location=self._meta.imaging_plane.targeted_structure) # Image Segmentation: diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index 2ef05bb68..d5565effc 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -327,7 +327,7 @@ def to_json(self) -> dict: def to_nwb(self, nwbfile: NWBFile) -> NWBFile: self._subject_metadata.to_nwb(nwbfile=nwbfile) - + self._equipment.to_nwb(nwbfile=nwbfile) extension = load_pynwb_extension(BehaviorMetadataSchema, 'ndx-aibs-behavior-ophys') nwb_metadata = extension( diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment.py index d1d9b9c78..4b8020fc6 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/equipment.py @@ -6,9 +6,9 @@ from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ JsonReadableInterface, LimsReadableInterface, NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ +from allensdk.brain_observatory.behavior.data_objects.base \ .writable_interfaces import \ - JsonWritableInterface + JsonWritableInterface, NwbWritableInterface from allensdk.internal.api import PostgresQueryMixin @@ -18,7 +18,8 @@ class EquipmentType(Enum): class Equipment(DataObject, JsonReadableInterface, LimsReadableInterface, - NwbReadableInterface, JsonWritableInterface): + NwbReadableInterface, JsonWritableInterface, + NwbWritableInterface): """the name of the experimental rig.""" def __init__(self, equipment_name: str): super().__init__(name="equipment_name", value=equipment_name) @@ -47,6 +48,22 @@ def from_nwb(cls, nwbfile: NWBFile) -> "Equipment": metadata = nwbfile.lab_meta_data['metadata'] return cls(equipment_name=metadata.equipment_name) + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + if self.type == EquipmentType.MESOSCOPE: + device_config = { + "name": self.value, + "description": "Allen Brain Observatory - Mesoscope 2P Rig" + } + else: + device_config = { + "name": self.value, + "description": "Allen Brain Observatory - Scientifica 2P " + "Rig", + "manufacturer": "Scientifica" + } + nwbfile.create_device(**device_config) + return nwbfile + @property def type(self): if self.value.startswith('MESO'): diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_plane.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_plane.py index 643ae02b7..c124ff743 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_plane.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/imaging_plane.py @@ -1,11 +1,16 @@ +from typing import Optional + from pynwb import NWBFile from allensdk.brain_observatory.behavior.data_files import SyncFile from allensdk.brain_observatory.behavior.data_objects import DataObject, \ - StimulusTimestamps + StimulusTimestamps, BehaviorSessionId from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ InternalReadableInterface, JsonReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .subject_metadata.reporter_line import \ + ReporterLine from allensdk.internal.api import PostgresQueryMixin @@ -13,11 +18,13 @@ class ImagingPlane(DataObject, InternalReadableInterface, JsonReadableInterface, NwbReadableInterface): def __init__(self, ophys_frame_rate: float, targeted_structure: str, - excitation_lambda: float): + excitation_lambda: float, + indicator: Optional[str]): super().__init__(name='imaging_plane', value=self) self._ophys_frame_rate = ophys_frame_rate self._targeted_structure = targeted_structure self._excitation_lambda = excitation_lambda + self._indicator = indicator @classmethod def from_internal(cls, ophys_experiment_id: int, @@ -29,9 +36,15 @@ def from_internal(cls, ophys_experiment_id: int, sync_file=sync_file) targeted_structure = cls._get_targeted_structure_from_lims( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + behavior_session_id = BehaviorSessionId.from_lims( + db=lims_db, ophys_experiment_id=ophys_experiment_id) + reporter_line = ReporterLine.from_lims( + behavior_session_id=behavior_session_id.value, lims_db=lims_db) + indicator = reporter_line.parse_indicator(warn=True) return cls(ophys_frame_rate=ophys_frame_rate, targeted_structure=targeted_structure, - excitation_lambda=excitation_lambda) + excitation_lambda=excitation_lambda, + indicator=indicator) @classmethod def from_json(cls, dict_repr: dict, @@ -40,9 +53,12 @@ def from_json(cls, dict_repr: dict, sync_file = SyncFile.from_json(dict_repr=dict_repr) ophys_fame_rate = cls._get_frame_rate_from_sync_file( sync_file=sync_file) + reporter_line = ReporterLine.from_json(dict_repr=dict_repr) + indicator = reporter_line.parse_indicator(warn=True) return cls(targeted_structure=targeted_structure, ophys_frame_rate=ophys_fame_rate, - excitation_lambda=excitation_lambda) + excitation_lambda=excitation_lambda, + indicator=indicator) @classmethod def from_nwb(cls, nwbfile: NWBFile) -> "ImagingPlane": @@ -53,9 +69,13 @@ def from_nwb(cls, nwbfile: NWBFile) -> "ImagingPlane": ophys_frame_rate = imaging_plane.imaging_rate targeted_structure = imaging_plane.location excitation_lambda = imaging_plane.excitation_lambda + + reporter_line = ReporterLine.from_nwb(nwbfile=nwbfile) + indicator = reporter_line.parse_indicator(warn=True) return cls(ophys_frame_rate=ophys_frame_rate, targeted_structure=targeted_structure, - excitation_lambda=excitation_lambda) + excitation_lambda=excitation_lambda, + indicator=indicator) @property def ophys_frame_rate(self) -> float: @@ -69,6 +89,10 @@ def targeted_structure(self) -> str: def excitation_lambda(self) -> float: return self._excitation_lambda + @property + def indicator(self) -> Optional[str]: + return self._indicator + @staticmethod def _get_frame_rate_from_sync_file( sync_file: SyncFile) -> float: From 09ebbfde614aba70c42031b72822d2811d191257 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 29 Jun 2021 10:09:03 -0700 Subject: [PATCH 063/234] Removes indicator from subject_metadata since is part of cell specimen table now; Makes CellSpecimenTableMeta a DataObject --- .../data_objects/cell_specimen_table.py | 61 +++++++++++++------ .../subject_metadata/subject_metadata.py | 4 -- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py index 74fd021de..bd9efb21c 100644 --- a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py +++ b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py @@ -7,7 +7,8 @@ from allensdk.brain_observatory.behavior.data_objects import DataObject from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ - JsonReadableInterface, LimsReadableInterface, NwbReadableInterface + JsonReadableInterface, LimsReadableInterface, NwbReadableInterface, \ + InternalReadableInterface from allensdk.brain_observatory.behavior.data_objects.base \ .writable_interfaces import \ NwbWritableInterface @@ -27,8 +28,10 @@ from allensdk.internal.api import PostgresQueryMixin -class CellSpecimenTableMeta: +class CellSpecimenTableMeta(DataObject, InternalReadableInterface, + JsonReadableInterface, NwbReadableInterface): def __init__(self, imaging_plane: ImagingPlane, emission_lambda=520.0): + super().__init__(name='cell_spcimen_meta', value=self) self._emission_lambda = emission_lambda self._imaging_plane = imaging_plane @@ -40,15 +43,50 @@ def emission_lambda(self): def imaging_plane(self): return self._imaging_plane + @classmethod + def from_internal(cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> "CellSpecimenTableMeta": + imaging_plane_meta = ImagingPlane.from_internal( + ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) + return cls(imaging_plane=imaging_plane_meta) + + @classmethod + def from_json(cls, dict_repr: dict) -> "CellSpecimenTableMeta": + imaging_plane_meta = ImagingPlane.from_json(dict_repr=dict_repr) + return cls(imaging_plane=imaging_plane_meta) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "CellSpecimenTableMeta": + ophys_module = nwbfile.processing['ophys'] + image_seg = ophys_module.data_interfaces['image_segmentation'] + plane_segmentations = image_seg.plane_segmentations + cell_specimen_table = plane_segmentations['cell_specimen_table'] + + imaging_plane = cell_specimen_table.imaging_plane + optical_channel = imaging_plane.optical_channel[0] + emission_lambda = optical_channel.emission_lambda + + imaging_plane = ImagingPlane.from_nwb(nwbfile=nwbfile) + return CellSpecimenTableMeta(emission_lambda=emission_lambda, + imaging_plane=imaging_plane) + class CellSpecimenTable(DataObject, LimsReadableInterface, JsonReadableInterface, NwbReadableInterface, NwbWritableInterface): def __init__(self, cell_specimen_table: pd.DataFrame, meta: CellSpecimenTableMeta): - super().__init__(name='cell_specimen_table', value=cell_specimen_table) + super().__init__(name='cell_specimen_table', value=self) self._meta = meta + self._cell_specimen_table = cell_specimen_table + @property + def table(self) -> pd.DataFrame: + return self._cell_specimen_table + + @property + def meta(self) -> CellSpecimenTableMeta: + return self._meta @classmethod def from_lims(cls, ophys_experiment_id: int, @@ -84,9 +122,8 @@ def get_ophys_cell_segmentation_run_id() -> int: cell_specimen_table = cls._postprocess( cell_specimen_table=cell_specimen_table, fov_shape=fov_shape) - imaging_plane_meta = ImagingPlane.from_internal( + meta = CellSpecimenTableMeta.from_internal( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) - meta = CellSpecimenTableMeta(imaging_plane=imaging_plane_meta) return cls(cell_specimen_table=cell_specimen_table, meta=meta) @classmethod @@ -96,8 +133,7 @@ def from_json(cls, dict_repr: dict) -> "CellSpecimenTable": cell_specimen_table = cls._postprocess( cell_specimen_table=cell_specimen_table, fov_shape=fov_shape) - imaging_plane_meta = ImagingPlane.from_json(dict_repr=dict_repr) - meta = CellSpecimenTableMeta(imaging_plane=imaging_plane_meta) + meta = CellSpecimenTableMeta.from_json(dict_repr=dict_repr) return cls(cell_specimen_table=cell_specimen_table, meta=meta) @classmethod @@ -127,17 +163,8 @@ def _read_table(cell_specimen_table): df = df[df["valid_roi"]] return df - def _read_meta(cell_specimen_table) -> CellSpecimenTableMeta: - imaging_plane = cell_specimen_table.imaging_plane - optical_channel = imaging_plane.optical_channel[0] - emission_lambda = optical_channel.emission_lambda - - imaging_plane = ImagingPlane.from_nwb(nwbfile=nwbfile) - return CellSpecimenTableMeta(emission_lambda=emission_lambda, - imaging_plane=imaging_plane) - df = _read_table(cell_specimen_table=cell_specimen_table) - meta = _read_meta(cell_specimen_table=cell_specimen_table) + meta = CellSpecimenTableMeta.from_nwb(nwbfile=nwbfile) return cls(cell_specimen_table=df, meta=meta) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py index 6fadf6f14..710a07ed4 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/subject_metadata.py @@ -145,10 +145,6 @@ def age_in_days(self) -> Optional[int]: def reporter_line(self) -> Optional[str]: return self._reporter_line.value - @property - def indicator(self) -> Optional[str]: - return self._reporter_line.parse_indicator(warn=True) - @property def full_genotype(self) -> str: return self._full_genotype.value From 5c32217806e108897d4a7196a345efc33d46b8a0 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 29 Jun 2021 11:12:08 -0700 Subject: [PATCH 064/234] fixes bug with to_dict (properties not looked up on base class) --- .../data_objects/base/_data_object_abc.py | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py index 4a5ad7390..45fd25c2b 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py @@ -38,10 +38,6 @@ def name(self) -> str: def value(self) -> Any: return self._value - @classmethod - def _get_vars(cls): - return vars(cls) - def to_dict(self) -> dict: """ Serialize DataObject to dict @@ -87,9 +83,17 @@ def to_dict(self) -> dict: # Here, build onto the nested key structure newpath = path + [name] - def _get_keys_and_values(value: DataObject): + def _get_keys_and_values(base_value: DataObject): properties = [] - for name, value in value._get_properties().items(): + for name, value in base_value._get_properties().items(): + if value is base_value: + # skip properties that return self + # (leads to infinite recursion) + continue + if name == 'name': + # The name is the key + continue + if isinstance(value, DataObject): # The key will be the DataObject "name" field name = value._name @@ -98,7 +102,7 @@ def _get_keys_and_values(value: DataObject): pass properties.append((name, value, newpath)) return properties - properties = _get_keys_and_values(value=value) + properties = _get_keys_and_values(base_value=value) # Find the nested dict cur = res @@ -124,9 +128,10 @@ def _get_keys_and_values(value: DataObject): def _get_properties(self): """Returns all property names and values""" - vars_ = self._get_vars() - return {name: getattr(self, name) for name, value in vars_.items() - if isinstance(value, property)} + def is_prop(attr): + return isinstance(getattr(type(self), attr, None), property) + props = [attr for attr in dir(self) if is_prop(attr)] + return {name: getattr(self, name) for name in props} def __eq__(self, other: "DataObject"): if type(self) != type(other): From 1f653933ee586c8c0a54fc1d8b7918b313641135 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 29 Jun 2021 19:25:09 -0700 Subject: [PATCH 065/234] make test input json smaller; add csp tests; fix bugs --- .../data_objects/base/_data_object_abc.py | 2 +- .../data_objects/cell_specimen_table.py | 2 +- .../metadata/behavior_ophys_metadata.py | 2 + .../metadata/test_behavior_ophys_metadata.py | 13 +- .../data_objects/test_cell_specimen_table.py | 116 + .../data_objects/test_data/test_input.json | 10105 +--------------- 6 files changed, 142 insertions(+), 10098 deletions(-) create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_cell_specimen_table.py diff --git a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py index 45fd25c2b..e37a4eb40 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py @@ -93,7 +93,7 @@ def _get_keys_and_values(base_value: DataObject): if name == 'name': # The name is the key continue - + if isinstance(value, DataObject): # The key will be the DataObject "name" field name = value._name diff --git a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py index bd9efb21c..869f65b58 100644 --- a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py +++ b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py @@ -176,7 +176,7 @@ def to_nwb(self, nwbfile: NWBFile) -> NWBFile: Additional metadata not written to nwb yet, required to write cell specimen table """ - cell_roi_table = self.value.reset_index().set_index( + cell_roi_table = self.table.reset_index().set_index( 'cell_roi_id') metadata = nwbfile.lab_meta_data['metadata'] diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py index bc386e99f..1adadd40b 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_ophys_metadata.py @@ -97,6 +97,8 @@ def from_nwb(cls, nwbfile: NWBFile) -> "BehaviorOphysMetadata": def to_nwb(self, nwbfile: NWBFile) -> NWBFile: self._behavior_metadata.subject_metadata.to_nwb(nwbfile=nwbfile) + self._behavior_metadata.equipment.to_nwb(nwbfile=nwbfile) + nwb_extension = load_pynwb_extension( OphysBehaviorMetadataSchema, 'ndx-aibs-behavior-ophys') diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py index 3601ee128..e0a6c2996 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py @@ -47,7 +47,7 @@ TestBehaviorMetadata -class TestBO: +class TestBOM: @classmethod def setup_class(cls): cls.meta = cls._get_meta() @@ -96,7 +96,7 @@ def _get_mesoscope_meta(self): ) -class TestInternal(TestBO): +class TestInternal(TestBOM): @classmethod def setup_method(self, method): marks = getattr(method, 'pytestmark', None) @@ -124,11 +124,8 @@ def test_from_internal(self, meso): else: assert isinstance(bom.ophys_metadata, OphysExperimentMetadata) - def test_foo(self): - pass - -class TestJson(TestBO): +class TestJson(TestBOM): @classmethod def setup_method(self, method): dir = Path(__file__).parent.resolve() @@ -153,7 +150,7 @@ def test_from_json(self, meso): assert isinstance(bom.ophys_metadata, OphysExperimentMetadata) -class TestNWB(TestBO): +class TestNWB(TestBOM): def setup_method(self, method): self.meta = self._get_meta() self.nwbfile = pynwb.NWBFile( @@ -164,7 +161,7 @@ def setup_method(self, method): @pytest.mark.parametrize('meso', [True, False]) @pytest.mark.parametrize('roundtrip', [True, False]) - def test_read_write_nwb(self, roundtrip, cell_specimen_table, + def test_read_write_nwb(self, roundtrip, data_object_roundtrip_fixture, meso): if meso: self.meta = self._get_mesoscope_meta() diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_cell_specimen_table.py b/allensdk/test/brain_observatory/behavior/data_objects/test_cell_specimen_table.py new file mode 100644 index 000000000..56e6bcce7 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/test_cell_specimen_table.py @@ -0,0 +1,116 @@ +import json +from datetime import datetime +from pathlib import Path +import numpy as np +import pynwb + +import pytest + +from allensdk.brain_observatory.behavior.data_objects.cell_specimen_table \ + import \ + CellSpecimenTable, CellSpecimenTableMeta +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.imaging_plane import \ + ImagingPlane +from allensdk.core.auth_config import LIMS_DB_CREDENTIAL_MAP +from allensdk.internal.api import db_connection_creator +from allensdk.test.brain_observatory.behavior.data_objects.metadata\ + .test_behavior_ophys_metadata import \ + TestBOM + + +class TestLims: + @classmethod + def setup_class(cls): + cls.ophys_experiment_id = 994278291 + cls.expected_meta = CellSpecimenTableMeta( + emission_lambda=520.0, + imaging_plane=ImagingPlane( + excitation_lambda=910.0, + indicator='GCaMP6f', + ophys_frame_rate=60.0, + targeted_structure='VISp' + ) + ) + + def setup_method(self, method): + marks = getattr(method, 'pytestmark', None) + if marks: + marks = [m.name for m in marks] + + # Will only create a dbconn if the test requires_bamboo + if 'requires_bamboo' in marks: + self.dbconn = db_connection_creator( + fallback_credentials=LIMS_DB_CREDENTIAL_MAP) + + @pytest.mark.requires_bamboo + def test_from_internal(self): + csp = CellSpecimenTable.from_lims( + ophys_experiment_id=self.ophys_experiment_id, lims_db=self.dbconn) + assert not csp.table.empty + assert csp.meta == self.expected_meta + + +class TestJson: + @classmethod + def setup_class(cls): + dir = Path(__file__).parent.resolve() + test_data_dir = dir / 'test_data' + with open(test_data_dir / 'test_input.json') as f: + dict_repr = json.load(f) + dict_repr = dict_repr['session_data'] + dict_repr['sync_file'] = str(test_data_dir / 'sync.h5') + dict_repr['behavior_stimulus_file'] = str(test_data_dir / + 'behavior_stimulus_file.pkl') + + cls.dict_repr = dict_repr + cls.expected_meta = CellSpecimenTableMeta( + emission_lambda=520.0, + imaging_plane=ImagingPlane( + excitation_lambda=910.0, + indicator='GCaMP6f', + ophys_frame_rate=np.nan, + targeted_structure='VISp' + ) + ) + + def test_from_json(self): + csp = CellSpecimenTable.from_json(dict_repr=self.dict_repr) + assert not csp.table.empty + assert csp.meta == self.expected_meta + + +class TestNWB: + @classmethod + def setup_class(cls): + tj = TestJson() + tj.setup_class() + cls.cell_specimen_table = CellSpecimenTable.from_json( + dict_repr=tj.dict_repr) + + def setup_method(self, method): + self.nwbfile = pynwb.NWBFile( + session_description='asession', + identifier='1234', + session_start_time=datetime.now() + ) + + # Write metadata, since csp requires other metdata + tbom = TestBOM() + tbom.setup_class() + bom = tbom.meta + bom.to_nwb(nwbfile=self.nwbfile) + + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_read_write_nwb(self, roundtrip, + data_object_roundtrip_fixture): + self.cell_specimen_table.to_nwb(nwbfile=self.nwbfile) + + if roundtrip: + obt = data_object_roundtrip_fixture( + nwbfile=self.nwbfile, + data_object_cls=CellSpecimenTable) + else: + obt = self.cell_specimen_table.from_nwb(nwbfile=self.nwbfile) + + assert obt == self.cell_specimen_table diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_data/test_input.json b/allensdk/test/brain_observatory/behavior/data_objects/test_data/test_input.json index 0ae28f85f..76d25b86f 100755 --- a/allensdk/test/brain_observatory/behavior/data_objects/test_data/test_input.json +++ b/allensdk/test/brain_observatory/behavior/data_objects/test_data/test_input.json @@ -61,10151 +61,80 @@ "cell_roi_id": { "0": 1080639771, "1": 1080639729, - "2": 1080639652, - "3": 1080639639, - "4": 1080639619, - "5": 1080639602, - "6": 1080639634, - "7": 1080639671, - "8": 1080639724, - "9": 1080639615, - "10": 1080639719, - "11": 1080639646, - "12": 1080639734, - "13": 1080639599, - "14": 1080639757, - "15": 1080639700, - "16": 1080639742, - "17": 1080639751, - "18": 1080639710, - "19": 1080639694, - "20": 1080639687, - "21": 1080639678, - "22": 1080639617, - "23": 1080639606, - "24": 1080639597, - "25": 1080639608, - "26": 1080639705, - "27": 1080639610, - "28": 1080639591, - "29": 1080639593, - "30": 1080639623, - "31": 1080639627, - "32": 1080639763, - "33": 1080639658, - "34": 1080639663 + "2": 1080639652 }, "cell_specimen_id": { "0": 1086633380, "1": 1086633339, - "2": 1086633332, - "3": 1086633316, - "4": 1086633303, - "5": 1086633291, - "6": 1086632579, - "7": 1086632521, - "8": 1086632450, - "9": 1086632408, - "10": 1086632371, - "11": 1086632312, - "12": 1086632294, - "13": 1086632264, - "14": 1086632192, - "15": 1086632159, - "16": 1086632005, - "17": 1086631914, - "18": 1086631720, - "19": 1086631620, - "20": 1086631567, - "21": 1086631514, - "22": 1086631455, - "23": 1086631390, - "24": 1086631342, - "25": 1086631288, - "26": 1086631205, - "27": 1086631138, - "28": 1086631077, - "29": 1086631018, - "30": 1086630818, - "31": 1086630755, - "32": 1086630685, - "33": 1086630543, - "34": 1086630477 + "2": 1086633332 }, "x": { "0": 422, "1": 185, - "2": 2, - "3": 165, - "4": 329, - "5": 214, - "6": 48, - "7": 305, - "8": 331, - "9": 23, - "10": 372, - "11": 270, - "12": 289, - "13": 398, - "14": 347, - "15": 225, - "16": 225, - "17": 223, - "18": 216, - "19": 361, - "20": 292, - "21": 429, - "22": 189, - "23": 298, - "24": 136, - "25": 111, - "26": 368, - "27": 252, - "28": 53, - "29": 310, - "30": 136, - "31": 301, - "32": 69, - "33": 169, - "34": 283 + "2": 2 }, "y": { "0": 147, "1": 2, - "2": 336, - "3": 461, - "4": 491, - "5": 373, - "6": 448, - "7": 296, - "8": 2, - "9": 387, - "10": 2, - "11": 460, - "12": 147, - "13": 384, - "14": 53, - "15": 237, - "16": 102, - "17": 71, - "18": 338, - "19": 251, - "20": 255, - "21": 269, - "22": 391, - "23": 378, - "24": 381, - "25": 417, - "26": 355, - "27": 421, - "28": 422, - "29": 422, - "30": 471, - "31": 454, - "32": 224, - "33": 322, - "34": 321 + "2": 336 }, "max_correction_up": { "0": 20.0, "1": 20.0, - "2": 20.0, - "3": 20.0, - "4": 20.0, - "5": 20.0, - "6": 20.0, - "7": 20.0, - "8": 20.0, - "9": 20.0, - "10": 20.0, - "11": 20.0, - "12": 20.0, - "13": 20.0, - "14": 20.0, - "15": 20.0, - "16": 20.0, - "17": 20.0, - "18": 20.0, - "19": 20.0, - "20": 20.0, - "21": 20.0, - "22": 20.0, - "23": 20.0, - "24": 20.0, - "25": 20.0, - "26": 20.0, - "27": 20.0, - "28": 20.0, - "29": 20.0, - "30": 20.0, - "31": 20.0, - "32": 20.0, - "33": 20.0, - "34": 20.0 + "2": 20.0 }, "max_correction_right": { "0": 10.0, "1": 10.0, - "2": 10.0, - "3": 10.0, - "4": 10.0, - "5": 10.0, - "6": 10.0, - "7": 10.0, - "8": 10.0, - "9": 10.0, - "10": 10.0, - "11": 10.0, - "12": 10.0, - "13": 10.0, - "14": 10.0, - "15": 10.0, - "16": 10.0, - "17": 10.0, - "18": 10.0, - "19": 10.0, - "20": 10.0, - "21": 10.0, - "22": 10.0, - "23": 10.0, - "24": 10.0, - "25": 10.0, - "26": 10.0, - "27": 10.0, - "28": 10.0, - "29": 10.0, - "30": 10.0, - "31": 10.0, - "32": 10.0, - "33": 10.0, - "34": 10.0 + "2": 10.0 }, "max_correction_down": { "0": 10.0, "1": 10.0, - "2": 10.0, - "3": 10.0, - "4": 10.0, - "5": 10.0, - "6": 10.0, - "7": 10.0, - "8": 10.0, - "9": 10.0, - "10": 10.0, - "11": 10.0, - "12": 10.0, - "13": 10.0, - "14": 10.0, - "15": 10.0, - "16": 10.0, - "17": 10.0, - "18": 10.0, - "19": 10.0, - "20": 10.0, - "21": 10.0, - "22": 10.0, - "23": 10.0, - "24": 10.0, - "25": 10.0, - "26": 10.0, - "27": 10.0, - "28": 10.0, - "29": 10.0, - "30": 10.0, - "31": 10.0, - "32": 10.0, - "33": 10.0, - "34": 10.0 + "2": 10.0 }, "max_correction_left": { "0": 0.0, "1": 0.0, - "2": 0.0, - "3": 0.0, - "4": 0.0, - "5": 0.0, - "6": 0.0, - "7": 0.0, - "8": 0.0, - "9": 0.0, - "10": 0.0, - "11": 0.0, - "12": 0.0, - "13": 0.0, - "14": 0.0, - "15": 0.0, - "16": 0.0, - "17": 0.0, - "18": 0.0, - "19": 0.0, - "20": 0.0, - "21": 0.0, - "22": 0.0, - "23": 0.0, - "24": 0.0, - "25": 0.0, - "26": 0.0, - "27": 0.0, - "28": 0.0, - "29": 0.0, - "30": 0.0, - "31": 0.0, - "32": 0.0, - "33": 0.0, - "34": 0.0 + "2": 0.0 }, "valid_roi": { "0": false, "1": false, - "2": false, - "3": false, - "4": false, - "5": true, - "6": true, - "7": true, - "8": false, - "9": true, - "10": false, - "11": false, - "12": true, - "13": true, - "14": false, - "15": true, - "16": true, - "17": true, - "18": true, - "19": true, - "20": true, - "21": true, - "22": true, - "23": true, - "24": true, - "25": true, - "26": true, - "27": true, - "28": true, - "29": false, - "30": false, - "31": false, - "32": true, - "33": true, - "34": true + "2": false }, "height": { - "0": 13, - "1": 10, - "2": 14, - "3": 18, - "4": 15, - "5": 18, - "6": 12, - "7": 20, - "8": 9, - "9": 18, - "10": 19, - "11": 14, - "12": 19, - "13": 13, - "14": 21, - "15": 15, - "16": 18, - "17": 16, - "18": 21, - "19": 14, - "20": 18, - "21": 13, - "22": 17, - "23": 17, - "24": 14, - "25": 16, - "26": 13, - "27": 14, - "28": 18, - "29": 16, - "30": 19, - "31": 21, - "32": 27, - "33": 13, - "34": 16 + "0": 1, + "1": 1, + "2": 1 }, "width": { - "0": 13, - "1": 18, - "2": 12, - "3": 12, - "4": 16, - "5": 15, - "6": 18, - "7": 11, - "8": 22, - "9": 13, - "10": 14, - "11": 15, - "12": 14, - "13": 16, - "14": 11, - "15": 14, - "16": 23, - "17": 13, - "18": 24, - "19": 13, - "20": 15, - "21": 18, - "22": 13, - "23": 14, - "24": 12, - "25": 15, - "26": 23, - "27": 13, - "28": 12, - "29": 12, - "30": 13, - "31": 13, - "32": 15, - "33": 15, - "34": 19 + "0": 1, + "1": 1, + "2": 1 }, "mask_image_plane": { "0": 0, "1": 0, - "2": 0, - "3": 0, - "4": 0, - "5": 0, - "6": 0, - "7": 0, - "8": 0, - "9": 0, - "10": 0, - "11": 0, - "12": 0, - "13": 0, - "14": 0, - "15": 0, - "16": 0, - "17": 0, - "18": 0, - "19": 0, - "20": 0, - "21": 0, - "22": 0, - "23": 0, - "24": 0, - "25": 0, - "26": 0, - "27": 0, - "28": 0, - "29": 0, - "30": 0, - "31": 0, - "32": 0, - "33": 0, - "34": 0 + "2": 0 }, "roi_mask": { "0": [ [ - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false ] ], "1": [ [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - false ] ], "2": [ [ - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false - ] - ], - "3": [ - [ - false, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false - ] - ], - "4": [ - [ - false, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false - ] - ], - "5": [ - [ - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false - ] - ], - "6": [ - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false - ] - ], - "7": [ - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - false - ] - ], - "8": [ - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ] - ], - "9": [ - [ - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false - ] - ], - "10": [ - [ - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false - ] - ], - "11": [ - [ - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false - ] - ], - "12": [ - [ - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false - ] - ], - "13": [ - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - false, - false - ] - ], - "14": [ - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false - ] - ], - "15": [ - [ - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false - ] - ], - "16": [ - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false, - false - ] - ], - "17": [ - [ - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - false - ] - ], - "18": [ - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ] - ], - "19": [ - [ - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ] - ], - "20": [ - [ - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false - ] - ], - "21": [ - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ] - ], - "22": [ - [ - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false, - false - ] - ], - "23": [ - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false - ] - ], - "24": [ - [ - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false - ] - ], - "25": [ - [ - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false - ] - ], - "26": [ - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ] - ], - "27": [ - [ - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ] - ], - "28": [ - [ - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false - ] - ], - "29": [ - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ] - ], - "30": [ - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false - ] - ], - "31": [ - [ - false, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ] - ], - "32": [ - [ - false, - false, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false - ] - ], - "33": [ - [ - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false - ] - ], - "34": [ - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false - ], - [ - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false - ], - [ - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false - ], - [ - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false - ], - [ - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false ] ] } } } -} +} \ No newline at end of file From ca011f31a761a286f3faaffacf697db4220dcb87 Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 30 Jun 2021 06:56:40 -0700 Subject: [PATCH 066/234] linting --- .../behavior/data_objects/cell_specimen_table.py | 10 ++-------- .../mesoscope_experiment_metadata.py | 3 --- .../metadata/test_behavior_ophys_metadata.py | 7 ------- 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py index 869f65b58..8d903b6be 100644 --- a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py +++ b/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py @@ -12,12 +12,6 @@ from allensdk.brain_observatory.behavior.data_objects.base \ .writable_interfaces import \ NwbWritableInterface -from allensdk.brain_observatory.behavior.data_objects.metadata \ - .behavior_metadata.equipment import \ - EquipmentType -from allensdk.brain_observatory.behavior.data_objects.metadata \ - .behavior_ophys_metadata import \ - BehaviorOphysMetadata from allensdk.brain_observatory.behavior.data_objects.metadata \ .ophys_experiment_metadata.field_of_view_shape import \ FieldOfViewShape @@ -153,8 +147,8 @@ def _read_table(cell_specimen_table): df = df.rename(columns={'image_mask': 'roi_mask'}) df.index.rename('cell_roi_id', inplace=True) - df['cell_specimen_id'] = [None if csid == -1 else csid - for csid in df['cell_specimen_id'].values] + df['cell_specimen_id'] = [None if id_ == -1 else id_ + for id_ in df['cell_specimen_id'].values] df.reset_index(inplace=True) df.set_index('cell_specimen_id', inplace=True) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py index 35dadf770..4e560825f 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/ophys_experiment_metadata/mesoscope_experiment_metadata/mesoscope_experiment_metadata.py @@ -9,9 +9,6 @@ from allensdk.brain_observatory.behavior.data_objects.metadata \ .ophys_experiment_metadata.imaging_depth import \ ImagingDepth -from allensdk.brain_observatory.behavior.data_objects.metadata \ - .ophys_experiment_metadata.imaging_plane import \ - ImagingPlane from allensdk.brain_observatory.behavior.data_objects.metadata \ .ophys_experiment_metadata.mesoscope_experiment_metadata \ .imaging_plane_group import \ diff --git a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py index e0a6c2996..513f61630 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/metadata/test_behavior_ophys_metadata.py @@ -1,13 +1,9 @@ import json from pathlib import Path -import pandas as pd import pynwb import pytest -from allensdk.brain_observatory.behavior.data_objects.cell_specimen_table \ - import \ - CellSpecimenTable from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.equipment import \ Equipment @@ -23,9 +19,6 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.imaging_depth import \ ImagingDepth -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.imaging_plane import \ - ImagingPlane from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.mesoscope_experiment_metadata\ .imaging_plane_group import \ From 5b4c994e0d5b5c69a458bc1c1e638d5f58165503 Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 30 Jun 2021 07:57:25 -0700 Subject: [PATCH 067/234] removes incomplete to_json --- .../metadata/behavior_metadata/date_of_acquisition.py | 9 +-------- .../metadata/behavior_metadata/foraging_id.py | 9 +-------- .../data_objects/metadata/subject_metadata/age.py | 8 +------- .../metadata/subject_metadata/driver_line.py | 8 +------- .../metadata/subject_metadata/full_genotype.py | 8 +------- .../data_objects/metadata/subject_metadata/mouse_id.py | 8 +------- .../metadata/subject_metadata/reporter_line.py | 8 +------- 7 files changed, 7 insertions(+), 51 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py index a3ee631dc..77677efd9 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/date_of_acquisition.py @@ -9,15 +9,11 @@ from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ JsonReadableInterface, LimsReadableInterface, NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces import \ - JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin class DateOfAcquisition(DataObject, LimsReadableInterface, - JsonReadableInterface, NwbReadableInterface, - JsonWritableInterface): + JsonReadableInterface, NwbReadableInterface): """timestamp for when experiment was started in UTC""" def __init__(self, date_of_acquisition: float): super().__init__(name="date_of_acquisition", value=date_of_acquisition) @@ -29,9 +25,6 @@ def from_json(cls, dict_repr: dict) -> "DateOfAcquisition": doa = cls.to_utc(date_of_acquisition=doa) return cls(date_of_acquisition=doa) - def to_json(self) -> dict: - return {"stimulus_frame_rate": self.value} - @classmethod def from_lims( cls, behavior_session_id: int, diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py index 3466f1a4a..3b2bae420 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/foraging_id.py @@ -4,14 +4,10 @@ from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ JsonReadableInterface, LimsReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces import \ - JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin -class ForagingId(DataObject, LimsReadableInterface, JsonReadableInterface, - JsonWritableInterface): +class ForagingId(DataObject, LimsReadableInterface, JsonReadableInterface): """Foraging id""" def __init__(self, foraging_id: uuid.UUID): super().__init__(name="foraging_id", value=foraging_id) @@ -20,9 +16,6 @@ def __init__(self, foraging_id: uuid.UUID): def from_json(cls, dict_repr: dict) -> "ForagingId": pass - def to_json(self) -> dict: - return {"sex": self.value} - @classmethod def from_lims(cls, behavior_session_id: int, lims_db: PostgresQueryMixin) -> "ForagingId": diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py index 8cfcf7247..111ac436f 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/age.py @@ -8,14 +8,11 @@ from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ JsonReadableInterface, LimsReadableInterface, NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces import \ - JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin class Age(DataObject, JsonReadableInterface, LimsReadableInterface, - NwbReadableInterface, JsonWritableInterface): + NwbReadableInterface): """Age of animal (in days)""" def __init__(self, age: int): super().__init__(name="age_in_days", value=age) @@ -26,9 +23,6 @@ def from_json(cls, dict_repr: dict) -> "Age": age = cls._age_code_to_days(age=age) return cls(age=age) - def to_json(self) -> dict: - return {"sex": self.value} - @classmethod def from_lims(cls, behavior_session_id: int, lims_db: PostgresQueryMixin) -> "Age": diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py index d9c519384..1d0a8a34c 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/driver_line.py @@ -6,15 +6,12 @@ from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ JsonReadableInterface, LimsReadableInterface, NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces import \ - JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin, \ OneOrMoreResultExpectedError class DriverLine(DataObject, LimsReadableInterface, JsonReadableInterface, - NwbReadableInterface, JsonWritableInterface): + NwbReadableInterface): """the genotype name(s) of the driver line(s)""" def __init__(self, driver_line: List[str]): super().__init__(name="driver_line", value=driver_line) @@ -23,9 +20,6 @@ def __init__(self, driver_line: List[str]): def from_json(cls, dict_repr: dict) -> "DriverLine": return cls(driver_line=dict_repr['driver_line']) - def to_json(self) -> dict: - return {"sex": self.value} - @classmethod def from_lims(cls, behavior_session_id: int, lims_db: PostgresQueryMixin) -> "DriverLine": diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py index bc8ca187f..be9977fc2 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/full_genotype.py @@ -7,14 +7,11 @@ from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ JsonReadableInterface, LimsReadableInterface, NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces import \ - JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin class FullGenotype(DataObject, LimsReadableInterface, JsonReadableInterface, - NwbReadableInterface, JsonWritableInterface): + NwbReadableInterface): """the name of the subject's genotype""" def __init__(self, full_genotype: str): super().__init__(name="full_genotype", value=full_genotype) @@ -23,9 +20,6 @@ def __init__(self, full_genotype: str): def from_json(cls, dict_repr: dict) -> "FullGenotype": return cls(full_genotype=dict_repr['full_genotype']) - def to_json(self) -> dict: - return {"sex": self.value} - @classmethod def from_lims(cls, behavior_session_id: int, lims_db: PostgresQueryMixin) -> "FullGenotype": diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py index a76c30e59..d29b9069d 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/mouse_id.py @@ -4,14 +4,11 @@ from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ JsonReadableInterface, LimsReadableInterface, NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces import \ - JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin class MouseId(DataObject, LimsReadableInterface, JsonReadableInterface, - NwbReadableInterface, JsonWritableInterface): + NwbReadableInterface): """the LabTracks ID""" def __init__(self, mouse_id: int): super().__init__(name="mouse_id", value=mouse_id) @@ -22,9 +19,6 @@ def from_json(cls, dict_repr: dict) -> "MouseId": mouse_id = int(mouse_id) return cls(mouse_id=mouse_id) - def to_json(self) -> dict: - return {"sex": self.value} - @classmethod def from_lims(cls, behavior_session_id: int, lims_db: PostgresQueryMixin) -> "MouseId": diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py index ef01a916a..56fcfb838 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/subject_metadata/reporter_line.py @@ -7,15 +7,12 @@ from allensdk.brain_observatory.behavior.data_objects.base \ .readable_interfaces import \ JsonReadableInterface, LimsReadableInterface, NwbReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ - .writable_interfaces import \ - JsonWritableInterface from allensdk.internal.api import PostgresQueryMixin, \ OneOrMoreResultExpectedError class ReporterLine(DataObject, LimsReadableInterface, JsonReadableInterface, - NwbReadableInterface, JsonWritableInterface): + NwbReadableInterface): """the genotype name(s) of the reporter line(s)""" def __init__(self, reporter_line: Optional[str]): super().__init__(name="reporter_line", value=reporter_line) @@ -26,9 +23,6 @@ def from_json(cls, dict_repr: dict) -> "ReporterLine": reporter_line = cls.parse(reporter_line=reporter_line, warn=True) return cls(reporter_line=reporter_line) - def to_json(self) -> dict: - return {"sex": self.value} - @classmethod def from_lims(cls, behavior_session_id: int, lims_db: PostgresQueryMixin) -> "ReporterLine": From e96e3d4cfcaa661ef6f7c5fa579bb7d8b0d4e97c Mon Sep 17 00:00:00 2001 From: aamster Date: Wed, 30 Jun 2021 08:38:12 -0700 Subject: [PATCH 068/234] fixes doctest --- .../behavior/data_objects/base/_data_object_abc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py index e37a4eb40..d8794c94a 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/_data_object_abc.py @@ -54,7 +54,7 @@ def to_dict(self) -> dict: ... def __init__(self): ... super().__init__(name='simple', value=1) >>> s = Simple() - >>> s.to_dict() == {'simple': 1} + >>> assert s.to_dict() == {'simple': 1} >>> class B(DataObject): ... def __init__(self): @@ -71,7 +71,7 @@ def to_dict(self) -> dict: ... def prop2(self): ... return '@' >>> a = A(b=B()) - >>> a.to_dict() == {'a': {'b': '!'}, 'prop2': '@'} + >>> assert a.to_dict() == {'a': {'b': '!', 'prop2': '@'}} """ res = dict() q = deque([(self._name, self, [])]) From 373d9b87c8ac5fe4f7e2b41e7fe5c41888c5525c Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 12 Jul 2021 06:55:11 -0700 Subject: [PATCH 069/234] adds projections --- .../behavior/data_objects/projections.py | 154 ++++++++++++++++++ allensdk/brain_observatory/nwb/nwb_utils.py | 15 +- .../data_objects/test_data/avg_projection.png | Bin 0 -> 39966 bytes .../data_objects/test_data/max_projection.png | Bin 0 -> 74085 bytes .../data_objects/test_data/test_input.json | 2 + .../behavior/data_objects/test_projections.py | 127 +++++++++++++++ 6 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 allensdk/brain_observatory/behavior/data_objects/projections.py create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_data/avg_projection.png create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_data/max_projection.png create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_projections.py diff --git a/allensdk/brain_observatory/behavior/data_objects/projections.py b/allensdk/brain_observatory/behavior/data_objects/projections.py new file mode 100644 index 000000000..01dc9c4cc --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/projections.py @@ -0,0 +1,154 @@ +from SimpleITK import Image +from matplotlib import image as mpimg +from pynwb import NWBFile, ProcessingModule +from pynwb.base import Images +from pynwb.image import GrayscaleImage + +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + JsonReadableInterface, NwbReadableInterface, \ + InternalReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .writable_interfaces import \ + NwbWritableInterface +from allensdk.brain_observatory.behavior.image_api import ImageApi +from allensdk.brain_observatory.nwb.nwb_utils import get_image +from allensdk.internal.api import PostgresQueryMixin +from allensdk.internal.core.lims_utilities import safe_system_path + + +class Projections(DataObject, InternalReadableInterface, JsonReadableInterface, + NwbReadableInterface, NwbWritableInterface): + def __init__(self, max_projection: Image, avg_projection: Image): + super().__init__(name='projections', value=self) + self._max_projection = max_projection + self._avg_projection = avg_projection + + @property + def max_projection(self) -> Image: + return self._max_projection + + @property + def avg_projection(self) -> Image: + return self._avg_projection + + @classmethod + def from_internal(cls, ophys_experiment_id: int, + lims_db: PostgresQueryMixin) -> "Projections": + query = """ + SELECT + wkf.storage_directory || wkf.filename AS filepath, + wkft.name as wkfn + FROM ophys_experiments oe + JOIN ophys_cell_segmentation_runs ocsr + ON ocsr.ophys_experiment_id = oe.id + JOIN well_known_files wkf ON wkf.attachable_id = ocsr.id + JOIN well_known_file_types wkft + ON wkft.id = wkf.well_known_file_type_id + WHERE ocsr.current = 't' + AND wkf.attachable_type = 'OphysCellSegmentationRun' + AND wkft.name IN ('OphysMaxIntImage', + 'OphysAverageIntensityProjectionImage') + AND oe.id = {}; + """.format(ophys_experiment_id) + res = lims_db.select(query=query) + res['filepath'] = res['filepath'].apply(safe_system_path) + + def _get_pixel_size(): + query = """ + SELECT sc.resolution + FROM ophys_experiments oe + JOIN scans sc ON sc.image_id=oe.ophys_primary_image_id + WHERE oe.id = {}; + """.format(ophys_experiment_id) + return lims_db.fetchone(query, strict=True) + + pixel_size = _get_pixel_size() + + max_projection_filepath = \ + res[res['wkfn'] == 'OphysMaxIntImage'].iloc[0]['filepath'] + max_projection = cls._from_filepath(filepath=max_projection_filepath, + pixel_size=pixel_size) + + avg_projection_filepath = \ + (res[res['wkfn'] == 'OphysAverageIntensityProjectionImage'].iloc[0] + ['filepath']) + avg_projection = cls._from_filepath(filepath=avg_projection_filepath, + pixel_size=pixel_size) + return Projections(max_projection=max_projection, + avg_projection=avg_projection) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "Projections": + max_projection = get_image(nwbfile=nwbfile, name='max_projection', + module='ophys') + avg_projection = get_image(nwbfile=nwbfile, name='average_image', + module='ophys') + return Projections(max_projection=max_projection, + avg_projection=avg_projection) + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + def _add_image(image_data: Image, image_name: str): + MODULE_NAME = 'ophys' + description = '{} image at pixels/cm resolution'.format(image_name) + + if isinstance(image_data, Image): + data, spacing, unit = ImageApi.deserialize(image_data) + else: + raise ValueError("Not a supported image_data type: " + f"{type(image_data)}") + + assert spacing[0] == spacing[1] and len( + spacing) == 2 and unit == 'mm' + + if MODULE_NAME not in nwbfile.processing: + ophys_mod = ProcessingModule(MODULE_NAME, + 'Ophys processing module') + nwbfile.add_processing_module(ophys_mod) + else: + ophys_mod = nwbfile.processing[MODULE_NAME] + + image = GrayscaleImage(image_name, + data, + resolution=spacing[0] / 10, + description=description) + + if 'images' not in ophys_mod.containers: + images = Images(name='images') + ophys_mod.add_data_interface(images) + else: + images = ophys_mod['images'] + images.add_image(image) + + _add_image(image_data=self._max_projection, + image_name='max_projection') + _add_image(image_data=self._avg_projection, image_name='average_image') + + return nwbfile + + @classmethod + def from_json(cls, dict_repr: dict) -> "Projections": + max_projection_filepath = dict_repr['max_projection_file'] + avg_projection_filepath = \ + dict_repr['average_intensity_projection_image_file'] + pixel_size = dict_repr['surface_2p_pixel_size_um'] + + max_projection = cls._from_filepath(filepath=max_projection_filepath, + pixel_size=pixel_size) + avg_projection = cls._from_filepath(filepath=avg_projection_filepath, + pixel_size=pixel_size) + return Projections(max_projection=max_projection, + avg_projection=avg_projection) + + @staticmethod + def _from_filepath(filepath: str, pixel_size: float) -> Image: + """ + :param filepath + path to image + :param pixel_size + pixel size in um + """ + max_projection = mpimg.imread(filepath) + return ImageApi.serialize(max_projection, [pixel_size / 1000., + pixel_size / 1000.], 'mm') diff --git a/allensdk/brain_observatory/nwb/nwb_utils.py b/allensdk/brain_observatory/nwb/nwb_utils.py index 591364a25..ef5a2cc9e 100644 --- a/allensdk/brain_observatory/nwb/nwb_utils.py +++ b/allensdk/brain_observatory/nwb/nwb_utils.py @@ -2,6 +2,10 @@ # All of the omitted stimuli have a duration of 250ms as defined # by the Visual Behavior team. For questions about duration contact that # team. +from SimpleITK import Image +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.image_api import ImageApi def get_column_name(table_cols: list, @@ -49,4 +53,13 @@ def set_omitted_stop_time(stimulus_table: pd.DataFrame, end_time = start_time + omitted_time_duration row['stop_time'] = end_time row['duration'] = omitted_time_duration - stimulus_table.iloc[omitted_row_idx] = row \ No newline at end of file + stimulus_table.iloc[omitted_row_idx] = row + + +def get_image(nwbfile: NWBFile, name: str, module: str) -> Image: + nwb_img = nwbfile.modules[module].get_data_interface('images')[name] + data = nwb_img.data + resolution = nwb_img.resolution # px/cm + spacing = [resolution * 10, resolution * 10] + + return ImageApi.serialize(data, spacing, 'mm') diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_data/avg_projection.png b/allensdk/test/brain_observatory/behavior/data_objects/test_data/avg_projection.png new file mode 100644 index 0000000000000000000000000000000000000000..e6d627dc95eef364733cac95532efc2196e5320a GIT binary patch literal 39966 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 P00000NkvXXu0mjfOEjS? literal 0 HcmV?d00001 diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_data/test_input.json b/allensdk/test/brain_observatory/behavior/data_objects/test_data/test_input.json index 76d25b86f..9e0cbda4a 100755 --- a/allensdk/test/brain_observatory/behavior/data_objects/test_data/test_input.json +++ b/allensdk/test/brain_observatory/behavior/data_objects/test_data/test_input.json @@ -18,6 +18,8 @@ "movie_width": 451, "container_id": 5678, "surface_2p_pixel_size_um": 0.78125, + "max_projection_file": "max_projection.png", + "average_intensity_projection_image_file": "avg_projection.png", "date_of_acquisition": "2020-12-17 10:01:12", "external_specimen_name": 544261, "targeted_structure": "VISp", diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_projections.py b/allensdk/test/brain_observatory/behavior/data_objects/test_projections.py new file mode 100644 index 000000000..8cb06e491 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/test_projections.py @@ -0,0 +1,127 @@ +import json +from datetime import datetime +from pathlib import Path +import numpy as np +import pynwb + +import pytest +from skimage import io + +from allensdk.brain_observatory.behavior.data_objects.cell_specimen_table \ + import \ + CellSpecimenTable, CellSpecimenTableMeta +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .ophys_experiment_metadata.imaging_plane import \ + ImagingPlane +from allensdk.brain_observatory.behavior.data_objects.projections import \ + Projections +from allensdk.brain_observatory.behavior.image_api import ImageApi +from allensdk.core.auth_config import LIMS_DB_CREDENTIAL_MAP +from allensdk.internal.api import db_connection_creator +from allensdk.test.brain_observatory.behavior.data_objects.metadata\ + .test_behavior_ophys_metadata import \ + TestBOM + + +class TestLims: + @classmethod + def setup_class(cls): + cls.ophys_experiment_id = 994278291 + + dir = Path(__file__).parent.resolve() + test_data_dir = dir / 'test_data' + + cls.expected_max = Projections._from_filepath( + filepath=str(test_data_dir / 'max_projection.png'), + pixel_size=.78125) + cls.expected_max = ImageApi.deserialize(img=cls.expected_max) + + cls.expected_avg = Projections._from_filepath( + filepath=str(test_data_dir / 'avg_projection.png'), + pixel_size=.78125) + cls.expected_avg = ImageApi.deserialize(img=cls.expected_avg) + + def setup_method(self, method): + marks = getattr(method, 'pytestmark', None) + if marks: + marks = [m.name for m in marks] + + # Will only create a dbconn if the test requires_bamboo + if 'requires_bamboo' in marks: + self.dbconn = db_connection_creator( + fallback_credentials=LIMS_DB_CREDENTIAL_MAP) + + @pytest.mark.requires_bamboo + def test_from_internal(self): + projections = Projections.from_internal( + ophys_experiment_id=self.ophys_experiment_id, lims_db=self.dbconn) + max = ImageApi.deserialize(img=projections.max_projection) + avg = ImageApi.deserialize(img=projections.avg_projection) + + assert max == self.expected_max + assert avg == self.expected_avg + + +class TestJson: + @classmethod + def setup_class(cls): + dir = Path(__file__).parent.resolve() + test_data_dir = dir / 'test_data' + with open(test_data_dir / 'test_input.json') as f: + dict_repr = json.load(f) + dict_repr = dict_repr['session_data'] + dict_repr['max_projection_file'] = test_data_dir / \ + dict_repr['max_projection_file'] + dict_repr['average_intensity_projection_image_file'] = \ + test_data_dir /\ + dict_repr['average_intensity_projection_image_file'] + + cls.expected_max = Projections._from_filepath( + filepath=str(test_data_dir / 'max_projection.png'), + pixel_size=.78125) + cls.expected_max = ImageApi.deserialize(img=cls.expected_max) + + cls.expected_avg = Projections._from_filepath( + filepath=str(test_data_dir / 'avg_projection.png'), + pixel_size=.78125) + cls.expected_avg = ImageApi.deserialize(img=cls.expected_avg) + + cls.dict_repr = dict_repr + + def test_from_json(self): + projections = Projections.from_json(dict_repr=self.dict_repr) + max = ImageApi.deserialize(img=projections.max_projection) + avg = ImageApi.deserialize(img=projections.avg_projection) + + assert max == self.expected_max + assert avg == self.expected_avg + + +class TestNWB: + @classmethod + def setup_class(cls): + tj = TestJson() + tj.setup_class() + cls.projections = Projections.from_json( + dict_repr=tj.dict_repr) + + def setup_method(self, method): + self.nwbfile = pynwb.NWBFile( + session_description='asession', + identifier='1234', + session_start_time=datetime.now() + ) + + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_read_write_nwb(self, roundtrip, + data_object_roundtrip_fixture): + self.projections.to_nwb(nwbfile=self.nwbfile) + + if roundtrip: + obt = data_object_roundtrip_fixture( + nwbfile=self.nwbfile, + data_object_cls=Projections) + else: + obt = self.projections.from_nwb(nwbfile=self.nwbfile) + + assert obt == self.projections From 0e77ca597eb7f49f86c9dc8b550f765eeadc6a14 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 12 Jul 2021 07:59:47 -0700 Subject: [PATCH 070/234] projections returns AllenSDK Image abstraction, not simpleitk --- .../behavior/data_objects/projections.py | 13 ++++---- allensdk/brain_observatory/nwb/nwb_utils.py | 9 +++--- .../behavior/data_objects/test_projections.py | 30 ++++--------------- 3 files changed, 15 insertions(+), 37 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/projections.py b/allensdk/brain_observatory/behavior/data_objects/projections.py index 01dc9c4cc..4b221a64e 100644 --- a/allensdk/brain_observatory/behavior/data_objects/projections.py +++ b/allensdk/brain_observatory/behavior/data_objects/projections.py @@ -1,4 +1,3 @@ -from SimpleITK import Image from matplotlib import image as mpimg from pynwb import NWBFile, ProcessingModule from pynwb.base import Images @@ -12,7 +11,7 @@ from allensdk.brain_observatory.behavior.data_objects.base\ .writable_interfaces import \ NwbWritableInterface -from allensdk.brain_observatory.behavior.image_api import ImageApi +from allensdk.brain_observatory.behavior.image_api import ImageApi, Image from allensdk.brain_observatory.nwb.nwb_utils import get_image from allensdk.internal.api import PostgresQueryMixin from allensdk.internal.core.lims_utilities import safe_system_path @@ -93,11 +92,7 @@ def _add_image(image_data: Image, image_name: str): MODULE_NAME = 'ophys' description = '{} image at pixels/cm resolution'.format(image_name) - if isinstance(image_data, Image): - data, spacing, unit = ImageApi.deserialize(image_data) - else: - raise ValueError("Not a supported image_data type: " - f"{type(image_data)}") + data, spacing, unit = image_data assert spacing[0] == spacing[1] and len( spacing) == 2 and unit == 'mm' @@ -150,5 +145,7 @@ def _from_filepath(filepath: str, pixel_size: float) -> Image: pixel size in um """ max_projection = mpimg.imread(filepath) - return ImageApi.serialize(max_projection, [pixel_size / 1000., + img = ImageApi.serialize(max_projection, [pixel_size / 1000., pixel_size / 1000.], 'mm') + img = ImageApi.deserialize(img=img) + return img diff --git a/allensdk/brain_observatory/nwb/nwb_utils.py b/allensdk/brain_observatory/nwb/nwb_utils.py index ef5a2cc9e..a9c995464 100644 --- a/allensdk/brain_observatory/nwb/nwb_utils.py +++ b/allensdk/brain_observatory/nwb/nwb_utils.py @@ -2,10 +2,9 @@ # All of the omitted stimuli have a duration of 250ms as defined # by the Visual Behavior team. For questions about duration contact that # team. -from SimpleITK import Image from pynwb import NWBFile -from allensdk.brain_observatory.behavior.image_api import ImageApi +from allensdk.brain_observatory.behavior.image_api import ImageApi, Image def get_column_name(table_cols: list, @@ -57,9 +56,11 @@ def set_omitted_stop_time(stimulus_table: pd.DataFrame, def get_image(nwbfile: NWBFile, name: str, module: str) -> Image: - nwb_img = nwbfile.modules[module].get_data_interface('images')[name] + nwb_img = nwbfile.processing[module].get_data_interface('images')[name] data = nwb_img.data resolution = nwb_img.resolution # px/cm spacing = [resolution * 10, resolution * 10] - return ImageApi.serialize(data, spacing, 'mm') + img = ImageApi.serialize(data, spacing, 'mm') + img = ImageApi.deserialize(img=img) + return img diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_projections.py b/allensdk/test/brain_observatory/behavior/data_objects/test_projections.py index 8cb06e491..447b2a8c1 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/test_projections.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/test_projections.py @@ -1,26 +1,14 @@ import json from datetime import datetime from pathlib import Path -import numpy as np import pynwb import pytest -from skimage import io - -from allensdk.brain_observatory.behavior.data_objects.cell_specimen_table \ - import \ - CellSpecimenTable, CellSpecimenTableMeta -from allensdk.brain_observatory.behavior.data_objects.metadata\ - .ophys_experiment_metadata.imaging_plane import \ - ImagingPlane + from allensdk.brain_observatory.behavior.data_objects.projections import \ Projections -from allensdk.brain_observatory.behavior.image_api import ImageApi from allensdk.core.auth_config import LIMS_DB_CREDENTIAL_MAP from allensdk.internal.api import db_connection_creator -from allensdk.test.brain_observatory.behavior.data_objects.metadata\ - .test_behavior_ophys_metadata import \ - TestBOM class TestLims: @@ -34,12 +22,10 @@ def setup_class(cls): cls.expected_max = Projections._from_filepath( filepath=str(test_data_dir / 'max_projection.png'), pixel_size=.78125) - cls.expected_max = ImageApi.deserialize(img=cls.expected_max) cls.expected_avg = Projections._from_filepath( filepath=str(test_data_dir / 'avg_projection.png'), pixel_size=.78125) - cls.expected_avg = ImageApi.deserialize(img=cls.expected_avg) def setup_method(self, method): marks = getattr(method, 'pytestmark', None) @@ -55,11 +41,9 @@ def setup_method(self, method): def test_from_internal(self): projections = Projections.from_internal( ophys_experiment_id=self.ophys_experiment_id, lims_db=self.dbconn) - max = ImageApi.deserialize(img=projections.max_projection) - avg = ImageApi.deserialize(img=projections.avg_projection) - assert max == self.expected_max - assert avg == self.expected_avg + assert projections.max_projection == self.expected_max + assert projections.avg_projection == self.expected_avg class TestJson: @@ -79,22 +63,18 @@ def setup_class(cls): cls.expected_max = Projections._from_filepath( filepath=str(test_data_dir / 'max_projection.png'), pixel_size=.78125) - cls.expected_max = ImageApi.deserialize(img=cls.expected_max) cls.expected_avg = Projections._from_filepath( filepath=str(test_data_dir / 'avg_projection.png'), pixel_size=.78125) - cls.expected_avg = ImageApi.deserialize(img=cls.expected_avg) cls.dict_repr = dict_repr def test_from_json(self): projections = Projections.from_json(dict_repr=self.dict_repr) - max = ImageApi.deserialize(img=projections.max_projection) - avg = ImageApi.deserialize(img=projections.avg_projection) - assert max == self.expected_max - assert avg == self.expected_avg + assert projections.max_projection == self.expected_max + assert projections.avg_projection == self.expected_avg class TestNWB: From db2dc550056ec9425191daee24fd11e6bd270445 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 12 Jul 2021 09:15:13 -0700 Subject: [PATCH 071/234] rename CellSpecimenTable -> CellSpecimens adds roi_masks property --- ...ll_specimen_table.py => cell_specimens.py} | 40 ++++++++++--------- ...ecimen_table.py => test_cell_specimens.py} | 16 ++++---- 2 files changed, 30 insertions(+), 26 deletions(-) rename allensdk/brain_observatory/behavior/data_objects/{cell_specimen_table.py => cell_specimens.py} (91%) rename allensdk/test/brain_observatory/behavior/data_objects/{test_cell_specimen_table.py => test_cell_specimens.py} (89%) diff --git a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py b/allensdk/brain_observatory/behavior/data_objects/cell_specimens.py similarity index 91% rename from allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py rename to allensdk/brain_observatory/behavior/data_objects/cell_specimens.py index 8d903b6be..503c5648a 100644 --- a/allensdk/brain_observatory/behavior/data_objects/cell_specimen_table.py +++ b/allensdk/brain_observatory/behavior/data_objects/cell_specimens.py @@ -22,8 +22,8 @@ from allensdk.internal.api import PostgresQueryMixin -class CellSpecimenTableMeta(DataObject, InternalReadableInterface, - JsonReadableInterface, NwbReadableInterface): +class CellSpecimenMeta(DataObject, InternalReadableInterface, + JsonReadableInterface, NwbReadableInterface): def __init__(self, imaging_plane: ImagingPlane, emission_lambda=520.0): super().__init__(name='cell_spcimen_meta', value=self) self._emission_lambda = emission_lambda @@ -39,18 +39,18 @@ def imaging_plane(self): @classmethod def from_internal(cls, ophys_experiment_id: int, - lims_db: PostgresQueryMixin) -> "CellSpecimenTableMeta": + lims_db: PostgresQueryMixin) -> "CellSpecimenMeta": imaging_plane_meta = ImagingPlane.from_internal( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) return cls(imaging_plane=imaging_plane_meta) @classmethod - def from_json(cls, dict_repr: dict) -> "CellSpecimenTableMeta": + def from_json(cls, dict_repr: dict) -> "CellSpecimenMeta": imaging_plane_meta = ImagingPlane.from_json(dict_repr=dict_repr) return cls(imaging_plane=imaging_plane_meta) @classmethod - def from_nwb(cls, nwbfile: NWBFile) -> "CellSpecimenTableMeta": + def from_nwb(cls, nwbfile: NWBFile) -> "CellSpecimenMeta": ophys_module = nwbfile.processing['ophys'] image_seg = ophys_module.data_interfaces['image_segmentation'] plane_segmentations = image_seg.plane_segmentations @@ -61,15 +61,15 @@ def from_nwb(cls, nwbfile: NWBFile) -> "CellSpecimenTableMeta": emission_lambda = optical_channel.emission_lambda imaging_plane = ImagingPlane.from_nwb(nwbfile=nwbfile) - return CellSpecimenTableMeta(emission_lambda=emission_lambda, - imaging_plane=imaging_plane) + return CellSpecimenMeta(emission_lambda=emission_lambda, + imaging_plane=imaging_plane) -class CellSpecimenTable(DataObject, LimsReadableInterface, - JsonReadableInterface, NwbReadableInterface, - NwbWritableInterface): +class CellSpecimens(DataObject, LimsReadableInterface, + JsonReadableInterface, NwbReadableInterface, + NwbWritableInterface): def __init__(self, cell_specimen_table: pd.DataFrame, - meta: CellSpecimenTableMeta): + meta: CellSpecimenMeta): super().__init__(name='cell_specimen_table', value=self) self._meta = meta self._cell_specimen_table = cell_specimen_table @@ -79,12 +79,16 @@ def table(self) -> pd.DataFrame: return self._cell_specimen_table @property - def meta(self) -> CellSpecimenTableMeta: + def roi_masks(self): + return self._cell_specimen_table[['cell_roi_id', 'roi_mask']] + + @property + def meta(self) -> CellSpecimenMeta: return self._meta @classmethod def from_lims(cls, ophys_experiment_id: int, - lims_db: PostgresQueryMixin) -> "CellSpecimenTable": + lims_db: PostgresQueryMixin) -> "CellSpecimens": def get_ophys_cell_segmentation_run_id() -> int: """Get the ophys cell segmentation run id associated with an ophys experiment id""" @@ -116,23 +120,23 @@ def get_ophys_cell_segmentation_run_id() -> int: cell_specimen_table = cls._postprocess( cell_specimen_table=cell_specimen_table, fov_shape=fov_shape) - meta = CellSpecimenTableMeta.from_internal( + meta = CellSpecimenMeta.from_internal( ophys_experiment_id=ophys_experiment_id, lims_db=lims_db) return cls(cell_specimen_table=cell_specimen_table, meta=meta) @classmethod - def from_json(cls, dict_repr: dict) -> "CellSpecimenTable": + def from_json(cls, dict_repr: dict) -> "CellSpecimens": cell_specimen_table = dict_repr['cell_specimen_table_dict'] fov_shape = FieldOfViewShape.from_json(dict_repr=dict_repr) cell_specimen_table = cls._postprocess( cell_specimen_table=cell_specimen_table, fov_shape=fov_shape) - meta = CellSpecimenTableMeta.from_json(dict_repr=dict_repr) + meta = CellSpecimenMeta.from_json(dict_repr=dict_repr) return cls(cell_specimen_table=cell_specimen_table, meta=meta) @classmethod def from_nwb(cls, nwbfile: NWBFile, - filter_invalid_rois=False) -> "CellSpecimenTable": + filter_invalid_rois=False) -> "CellSpecimens": # NOTE: ROI masks are stored in full frame width and height arrays ophys_module = nwbfile.processing['ophys'] image_seg = ophys_module.data_interfaces['image_segmentation'] @@ -158,7 +162,7 @@ def _read_table(cell_specimen_table): return df df = _read_table(cell_specimen_table=cell_specimen_table) - meta = CellSpecimenTableMeta.from_nwb(nwbfile=nwbfile) + meta = CellSpecimenMeta.from_nwb(nwbfile=nwbfile) return cls(cell_specimen_table=df, meta=meta) diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_cell_specimen_table.py b/allensdk/test/brain_observatory/behavior/data_objects/test_cell_specimens.py similarity index 89% rename from allensdk/test/brain_observatory/behavior/data_objects/test_cell_specimen_table.py rename to allensdk/test/brain_observatory/behavior/data_objects/test_cell_specimens.py index 56e6bcce7..a337a1dfa 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/test_cell_specimen_table.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/test_cell_specimens.py @@ -6,9 +6,9 @@ import pytest -from allensdk.brain_observatory.behavior.data_objects.cell_specimen_table \ +from allensdk.brain_observatory.behavior.data_objects.cell_specimens \ import \ - CellSpecimenTable, CellSpecimenTableMeta + CellSpecimens, CellSpecimenMeta from allensdk.brain_observatory.behavior.data_objects.metadata\ .ophys_experiment_metadata.imaging_plane import \ ImagingPlane @@ -23,7 +23,7 @@ class TestLims: @classmethod def setup_class(cls): cls.ophys_experiment_id = 994278291 - cls.expected_meta = CellSpecimenTableMeta( + cls.expected_meta = CellSpecimenMeta( emission_lambda=520.0, imaging_plane=ImagingPlane( excitation_lambda=910.0, @@ -45,7 +45,7 @@ def setup_method(self, method): @pytest.mark.requires_bamboo def test_from_internal(self): - csp = CellSpecimenTable.from_lims( + csp = CellSpecimens.from_lims( ophys_experiment_id=self.ophys_experiment_id, lims_db=self.dbconn) assert not csp.table.empty assert csp.meta == self.expected_meta @@ -64,7 +64,7 @@ def setup_class(cls): 'behavior_stimulus_file.pkl') cls.dict_repr = dict_repr - cls.expected_meta = CellSpecimenTableMeta( + cls.expected_meta = CellSpecimenMeta( emission_lambda=520.0, imaging_plane=ImagingPlane( excitation_lambda=910.0, @@ -75,7 +75,7 @@ def setup_class(cls): ) def test_from_json(self): - csp = CellSpecimenTable.from_json(dict_repr=self.dict_repr) + csp = CellSpecimens.from_json(dict_repr=self.dict_repr) assert not csp.table.empty assert csp.meta == self.expected_meta @@ -85,7 +85,7 @@ class TestNWB: def setup_class(cls): tj = TestJson() tj.setup_class() - cls.cell_specimen_table = CellSpecimenTable.from_json( + cls.cell_specimen_table = CellSpecimens.from_json( dict_repr=tj.dict_repr) def setup_method(self, method): @@ -109,7 +109,7 @@ def test_read_write_nwb(self, roundtrip, if roundtrip: obt = data_object_roundtrip_fixture( nwbfile=self.nwbfile, - data_object_cls=CellSpecimenTable) + data_object_cls=CellSpecimens) else: obt = self.cell_specimen_table.from_nwb(nwbfile=self.nwbfile) From ddf224575775f754d0e197430c4bb70a1901f5a6 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 12 Jul 2021 09:43:08 -0700 Subject: [PATCH 072/234] linting --- .../behavior/data_objects/cell_specimens.py | 2 +- .../behavior/data_objects/projections.py | 10 +++++----- allensdk/brain_observatory/nwb/nwb_utils.py | 8 +++++--- .../behavior/data_objects/test_projections.py | 6 +++--- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/cell_specimens.py b/allensdk/brain_observatory/behavior/data_objects/cell_specimens.py index 503c5648a..01a453ae8 100644 --- a/allensdk/brain_observatory/behavior/data_objects/cell_specimens.py +++ b/allensdk/brain_observatory/behavior/data_objects/cell_specimens.py @@ -79,7 +79,7 @@ def table(self) -> pd.DataFrame: return self._cell_specimen_table @property - def roi_masks(self): + def roi_masks(self) -> pd.DataFrame: return self._cell_specimen_table[['cell_roi_id', 'roi_mask']] @property diff --git a/allensdk/brain_observatory/behavior/data_objects/projections.py b/allensdk/brain_observatory/behavior/data_objects/projections.py index 4b221a64e..7ff36f7c7 100644 --- a/allensdk/brain_observatory/behavior/data_objects/projections.py +++ b/allensdk/brain_observatory/behavior/data_objects/projections.py @@ -8,7 +8,7 @@ .readable_interfaces import \ JsonReadableInterface, NwbReadableInterface, \ InternalReadableInterface -from allensdk.brain_observatory.behavior.data_objects.base\ +from allensdk.brain_observatory.behavior.data_objects.base \ .writable_interfaces import \ NwbWritableInterface from allensdk.brain_observatory.behavior.image_api import ImageApi, Image @@ -34,9 +34,9 @@ def avg_projection(self) -> Image: @classmethod def from_internal(cls, ophys_experiment_id: int, - lims_db: PostgresQueryMixin) -> "Projections": + lims_db: PostgresQueryMixin) -> "Projections": query = """ - SELECT + SELECT wkf.storage_directory || wkf.filename AS filepath, wkft.name as wkfn FROM ophys_experiments oe @@ -47,7 +47,7 @@ def from_internal(cls, ophys_experiment_id: int, ON wkft.id = wkf.well_known_file_type_id WHERE ocsr.current = 't' AND wkf.attachable_type = 'OphysCellSegmentationRun' - AND wkft.name IN ('OphysMaxIntImage', + AND wkft.name IN ('OphysMaxIntImage', 'OphysAverageIntensityProjectionImage') AND oe.id = {}; """.format(ophys_experiment_id) @@ -146,6 +146,6 @@ def _from_filepath(filepath: str, pixel_size: float) -> Image: """ max_projection = mpimg.imread(filepath) img = ImageApi.serialize(max_projection, [pixel_size / 1000., - pixel_size / 1000.], 'mm') + pixel_size / 1000.], 'mm') img = ImageApi.deserialize(img=img) return img diff --git a/allensdk/brain_observatory/nwb/nwb_utils.py b/allensdk/brain_observatory/nwb/nwb_utils.py index a9c995464..23da3d07d 100644 --- a/allensdk/brain_observatory/nwb/nwb_utils.py +++ b/allensdk/brain_observatory/nwb/nwb_utils.py @@ -29,7 +29,7 @@ def get_column_name(table_cols: list, def set_omitted_stop_time(stimulus_table: pd.DataFrame, - omitted_time_duration: float=0.25) -> None: + omitted_time_duration: float = 0.25) -> None: """ This function sets the stop time for a row that of a stimuli table that is a omitted stimuli. A omitted stimuli is a stimuli where a mouse is @@ -39,13 +39,15 @@ def set_omitted_stop_time(stimulus_table: pd.DataFrame, stop_time calculated and put into the row as data before writing to NWB. :param stimulus_table: pd.DataFrame that contains the stimuli presented to an experiment subject - :param omitted_time_duration: The duration in seconds of the expected length + :param omitted_time_duration: The duration in seconds of the expected + length of the omitted stimuli :return: stimulus_table_row: returns the same dictionary as inputted but with an additional entry for stop_time. """ - omitted_row_indexs = stimulus_table.index[stimulus_table['omitted']].tolist() + omitted_row_indexs = stimulus_table.index[ + stimulus_table['omitted']].tolist() for omitted_row_idx in omitted_row_indexs: row = stimulus_table.iloc[omitted_row_idx] start_time = row['start_time'] diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_projections.py b/allensdk/test/brain_observatory/behavior/data_objects/test_projections.py index 447b2a8c1..739b89cd7 100644 --- a/allensdk/test/brain_observatory/behavior/data_objects/test_projections.py +++ b/allensdk/test/brain_observatory/behavior/data_objects/test_projections.py @@ -1,8 +1,8 @@ import json from datetime import datetime from pathlib import Path -import pynwb +import pynwb import pytest from allensdk.brain_observatory.behavior.data_objects.projections import \ @@ -55,9 +55,9 @@ def setup_class(cls): dict_repr = json.load(f) dict_repr = dict_repr['session_data'] dict_repr['max_projection_file'] = test_data_dir / \ - dict_repr['max_projection_file'] + dict_repr['max_projection_file'] dict_repr['average_intensity_projection_image_file'] = \ - test_data_dir /\ + test_data_dir / \ dict_repr['average_intensity_projection_image_file'] cls.expected_max = Projections._from_filepath( From d7b34d16464323017bba08c5d5ac39495974c000 Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 12 Jul 2021 10:19:56 -0700 Subject: [PATCH 073/234] places filepaths query in inner function --- .../behavior/data_objects/projections.py | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/projections.py b/allensdk/brain_observatory/behavior/data_objects/projections.py index 7ff36f7c7..dc596c1b3 100644 --- a/allensdk/brain_observatory/behavior/data_objects/projections.py +++ b/allensdk/brain_observatory/behavior/data_objects/projections.py @@ -35,24 +35,26 @@ def avg_projection(self) -> Image: @classmethod def from_internal(cls, ophys_experiment_id: int, lims_db: PostgresQueryMixin) -> "Projections": - query = """ - SELECT - wkf.storage_directory || wkf.filename AS filepath, - wkft.name as wkfn - FROM ophys_experiments oe - JOIN ophys_cell_segmentation_runs ocsr - ON ocsr.ophys_experiment_id = oe.id - JOIN well_known_files wkf ON wkf.attachable_id = ocsr.id - JOIN well_known_file_types wkft - ON wkft.id = wkf.well_known_file_type_id - WHERE ocsr.current = 't' - AND wkf.attachable_type = 'OphysCellSegmentationRun' - AND wkft.name IN ('OphysMaxIntImage', - 'OphysAverageIntensityProjectionImage') - AND oe.id = {}; - """.format(ophys_experiment_id) - res = lims_db.select(query=query) - res['filepath'] = res['filepath'].apply(safe_system_path) + def _get_filepaths(): + query = """ + SELECT + wkf.storage_directory || wkf.filename AS filepath, + wkft.name as wkfn + FROM ophys_experiments oe + JOIN ophys_cell_segmentation_runs ocsr + ON ocsr.ophys_experiment_id = oe.id + JOIN well_known_files wkf ON wkf.attachable_id = ocsr.id + JOIN well_known_file_types wkft + ON wkft.id = wkf.well_known_file_type_id + WHERE ocsr.current = 't' + AND wkf.attachable_type = 'OphysCellSegmentationRun' + AND wkft.name IN ('OphysMaxIntImage', + 'OphysAverageIntensityProjectionImage') + AND oe.id = {}; + """.format(ophys_experiment_id) + res = lims_db.select(query=query) + res['filepath'] = res['filepath'].apply(safe_system_path) + return res def _get_pixel_size(): query = """ @@ -63,6 +65,7 @@ def _get_pixel_size(): """.format(ophys_experiment_id) return lims_db.fetchone(query, strict=True) + res = _get_filepaths() pixel_size = _get_pixel_size() max_projection_filepath = \ From d05b14a65b3150aae17f214df462aa91456dc75b Mon Sep 17 00:00:00 2001 From: aamster Date: Mon, 12 Jul 2021 11:43:02 -0700 Subject: [PATCH 074/234] correct typo --- .../brain_observatory/behavior/data_objects/projections.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/projections.py b/allensdk/brain_observatory/behavior/data_objects/projections.py index dc596c1b3..91f8a65e1 100644 --- a/allensdk/brain_observatory/behavior/data_objects/projections.py +++ b/allensdk/brain_observatory/behavior/data_objects/projections.py @@ -147,8 +147,8 @@ def _from_filepath(filepath: str, pixel_size: float) -> Image: :param pixel_size pixel size in um """ - max_projection = mpimg.imread(filepath) - img = ImageApi.serialize(max_projection, [pixel_size / 1000., - pixel_size / 1000.], 'mm') + img = mpimg.imread(filepath) + img = ImageApi.serialize(img, [pixel_size / 1000., + pixel_size / 1000.], 'mm') img = ImageApi.deserialize(img=img) return img From 82e8f687518c41907e3c18cb47e83d2f8d89d642 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 13 Jul 2021 08:21:34 -0700 Subject: [PATCH 075/234] adds licks --- .../behavior/data_objects/licks.py | 107 ++++++++++++++++++ .../behavior/data_objects/lims_util.py | 16 +++ .../behavior/data_objects/test_data/licks.pkl | Bin 0 -> 885 bytes .../behavior/data_objects/test_licks.py | 55 +++++++++ 4 files changed, 178 insertions(+) create mode 100644 allensdk/brain_observatory/behavior/data_objects/licks.py create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/lims_util.py create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_data/licks.pkl create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_licks.py diff --git a/allensdk/brain_observatory/behavior/data_objects/licks.py b/allensdk/brain_observatory/behavior/data_objects/licks.py new file mode 100644 index 000000000..c8d9c9c3b --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/licks.py @@ -0,0 +1,107 @@ +import logging + +import pandas as pd +from pynwb import NWBFile, TimeSeries, ProcessingModule + +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects import DataObject, \ + StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + StimulusFileReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .writable_interfaces import \ + NwbWritableInterface + + +class Licks(DataObject, StimulusFileReadableInterface, NwbReadableInterface, + NwbWritableInterface): + _logger = logging.getLogger(__name__) + + def __init__(self, licks: pd.DataFrame): + super().__init__(name='licks', value=licks) + + @classmethod + def from_stimulus_file(cls, stimulus_file: StimulusFile) -> "Licks": + """Get lick data from pkl file. + This function assumes that the first sensor in the list of + lick_sensors is the desired lick sensor. If this changes we need + to update to get the proper line. + + Since licks can occur outside of a trial context, the lick times + are extracted from the vsyncs and the frame number in `lick_events`. + Since we don't have a timestamp for when in "experiment time" the + vsync stream starts (from self.get_stimulus_timestamps), we compute + it by fitting a linear regression (frame number x time) for the + `start_trial` and `end_trial` events in the `trial_log`, to true + up these time streams. + + :returns: pd.DataFrame + Two columns: "time", which contains the sync time + of the licks that occurred in this session and "frame", + the frame numbers of licks that occurred in this session + """ + data = stimulus_file.data + + # Get licks from pickle file instead of sync + stimulus_timestamps = StimulusTimestamps.from_stimulus_file( + stimulus_file=stimulus_file) + lick_frames = (data["items"]["behavior"]["lick_sensors"][0] + ["lick_events"]) + + # there's an occasional bug where the number of logged + # frames is one greater than the number of vsync intervals. + # If the animal licked on this last frame it will cause an + # error here. This fixes the problem. + # see: https://github.com/AllenInstitute/visual_behavior_analysis + # /issues/572 # noqa: E501 + # & https://github.com/AllenInstitute/visual_behavior_analysis + # /issues/379 # noqa:E501 + # + # This bugfix copied from + # https://github.com/AllenInstitute/visual_behavior_analysis/blob + # /master/visual_behavior/translator/foraging2/extract.py#L640-L647 + + if len(lick_frames) > 0: + if lick_frames[-1] == len(stimulus_timestamps.value): + lick_frames = lick_frames[:-1] + cls._logger.error('removed last lick - ' + 'it fell outside of stimulus_timestamps ' + 'range') + + lick_times = \ + [stimulus_timestamps.value[frame] for frame in lick_frames] + df = pd.DataFrame({"timestamps": lick_times, "frame": lick_frames}) + return cls(licks=df) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "Licks": + if 'licking' in nwbfile.processing: + lick_module = nwbfile.processing['licking'] + licks = lick_module.get_data_interface('licks') + + df = pd.DataFrame({ + 'timestamps': licks.timestamps[:], + 'frame': licks.data[:] + }) + else: + df = pd.DataFrame({'time': [], 'frame': []}) + return cls(licks=df) + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + lick_timeseries = TimeSeries( + name='licks', + data=self.value['frame'].values, + timestamps=self.value['timestamps'].values, + description=('Timestamps and stimulus presentation ' + 'frame indices for lick events'), + unit='N/A' + ) + + # Add lick interface to nwb file, by way of a processing module: + licks_mod = ProcessingModule('licking', + 'Licking behavior processing module') + licks_mod.add_data_interface(lick_timeseries) + nwbfile.add_processing_module(licks_mod) + + return nwbfile diff --git a/allensdk/test/brain_observatory/behavior/data_objects/lims_util.py b/allensdk/test/brain_observatory/behavior/data_objects/lims_util.py new file mode 100644 index 000000000..0af3615f0 --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/lims_util.py @@ -0,0 +1,16 @@ +from allensdk.core.auth_config import LIMS_DB_CREDENTIAL_MAP +from allensdk.internal.api import db_connection_creator + + +class LimsTest: + """Helper class for testing LIMS. For each test, checks whether + bamboo is required and if so sets up a connection""" + def setup_method(self, method): + marks = getattr(method, 'pytestmark', None) + if marks: + marks = [m.name for m in marks] + + # Will only create a dbconn if the test requires_bamboo + if 'requires_bamboo' in marks: + self.dbconn = db_connection_creator( + fallback_credentials=LIMS_DB_CREDENTIAL_MAP) diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_data/licks.pkl b/allensdk/test/brain_observatory/behavior/data_objects/test_data/licks.pkl new file mode 100644 index 0000000000000000000000000000000000000000..91cd01df9e6d0edc8c0c364ea659e70f3642d26e GIT binary patch literal 885 zcmah|L2J}N6yEG6Yr9&cV6nXvJSg!JEC>n~7FrQBG=<(vm?YDk)Xi*|nWzg^^w5g% zJna*&Ui}9iJoyv+1O5iDBIuiB7j{e0Ib>euz3;vEz4_*~`{B6Lsu!%5OlC|6=}7V5 zNU?$=EI(w1J*w>q-hP88=z|w$bcnDyAD>IZm1IL56il)KR~q5U&Ty1I-E01_#`}kq zV0{so@fTbN3DZ=s7fb#;ek|#X0OB%uGuu{no5E|dD#~%wXHgAJ&Xi(fsuwGsj-)oK zN)5rms{;`(5wALAf??|vcbx>^;sN@h6ShxLtbv!Aamg*Dy?>u#LZ|U}zaN$C+wV|*o5}cIRe|~2(&DL-Syv}e}3OfKJ|aS zI{s=VU-}Pz?7#mgzx9#a|Hz&%WEb0u!wp{ z<|}S8+lW6K=dSgqYd Htdig_7IIR& literal 0 HcmV?d00001 diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_licks.py b/allensdk/test/brain_observatory/behavior/data_objects/test_licks.py new file mode 100644 index 000000000..4ce7a9d8b --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/test_licks.py @@ -0,0 +1,55 @@ +from datetime import datetime +from pathlib import Path + +import pandas as pd +import pynwb +import pytest + +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects.licks import Licks + + +class TestFromStimulusFile: + @classmethod + def setup_class(cls): + dir = Path(__file__).parent.resolve() + test_data_dir = dir / 'test_data' + + cls.stimulus_file = StimulusFile( + filepath=test_data_dir / 'behavior_stimulus_file.pkl') + expected = pd.read_pickle(str(test_data_dir / 'licks.pkl')) + cls.expected = Licks(licks=expected) + + def test_from_stimulus_file(self): + licks = Licks.from_stimulus_file(stimulus_file=self.stimulus_file) + assert licks == self.expected + + +class TestNWB: + @classmethod + def setup_class(cls): + tsf = TestFromStimulusFile() + tsf.setup_class() + cls.licks = Licks.from_stimulus_file( + stimulus_file=tsf.stimulus_file) + + def setup_method(self, method): + self.nwbfile = pynwb.NWBFile( + session_description='asession', + identifier='1234', + session_start_time=datetime.now() + ) + + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_read_write_nwb(self, roundtrip, + data_object_roundtrip_fixture): + self.licks.to_nwb(nwbfile=self.nwbfile) + + if roundtrip: + obt = data_object_roundtrip_fixture( + nwbfile=self.nwbfile, + data_object_cls=Licks) + else: + obt = self.licks.from_nwb(nwbfile=self.nwbfile) + + assert obt == self.licks From 8297060079ce3ab2ec989fedb0852f9cc4946ebf Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 13 Jul 2021 08:31:40 -0700 Subject: [PATCH 076/234] from_stimulus_file defines arg --- .../behavior/data_objects/base/readable_interfaces.py | 3 ++- .../metadata/behavior_metadata/behavior_metadata.py | 4 ++-- .../metadata/behavior_metadata/stimulus_frame_rate.py | 5 ++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces.py b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces.py index 409945a83..588f75f85 100644 --- a/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces.py +++ b/allensdk/brain_observatory/behavior/data_objects/base/readable_interfaces.py @@ -2,6 +2,7 @@ from pynwb import NWBFile +from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject @@ -80,7 +81,7 @@ class StimulusFileReadableInterface(abc.ABC): """Marks a data object as readable from stimulus file""" @classmethod @abc.abstractmethod - def from_stimulus_file(cls, *args) -> "DataObject": + def from_stimulus_file(cls, stimulus_file: StimulusFile) -> "DataObject": """Populate a DataObject from the stimulus file Returns diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index d5565effc..956968d9a 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -220,7 +220,7 @@ def from_internal( stimulus_timestamps = StimulusTimestamps.from_stimulus_file( stimulus_file=stimulus_file) stimulus_frame_rate = StimulusFrameRate.from_stimulus_file( - stimulus_timestamps=stimulus_timestamps) + stimulus_file=stimulus_file) session_type = SessionType.from_stimulus_file( stimulus_file=stimulus_file) date_of_acquisition = DateOfAcquisition.from_lims( @@ -257,7 +257,7 @@ def from_json(cls, dict_repr: dict) -> "BehaviorMetadata": stimulus_timestamps = StimulusTimestamps.from_stimulus_file( stimulus_file=stimulus_file) stimulus_frame_rate = StimulusFrameRate.from_stimulus_file( - stimulus_timestamps=stimulus_timestamps) + stimulus_file=stimulus_file) session_type = SessionType.from_stimulus_file( stimulus_file=stimulus_file) session_uuid = BehaviorSessionUUID.from_stimulus_file( diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py index 13b7bd7b5..37e4c4bed 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/stimulus_frame_rate.py @@ -1,5 +1,6 @@ from pynwb import NWBFile +from allensdk.brain_observatory.behavior.data_files import StimulusFile from allensdk.brain_observatory.behavior.data_objects import DataObject, \ StimulusTimestamps from allensdk.brain_observatory.behavior.data_objects.base \ @@ -16,7 +17,9 @@ def __init__(self, stimulus_frame_rate: float): @classmethod def from_stimulus_file( cls, - stimulus_timestamps: StimulusTimestamps) -> "StimulusFrameRate": + stimulus_file: StimulusFile) -> "StimulusFrameRate": + stimulus_timestamps = StimulusTimestamps.from_stimulus_file( + stimulus_file=stimulus_file) frame_rate = stimulus_timestamps.calc_frame_rate() return cls(stimulus_frame_rate=frame_rate) From 946b4b6af4ab34913c8c50f6e7b85f58850ae954 Mon Sep 17 00:00:00 2001 From: aamster Date: Tue, 13 Jul 2021 08:52:26 -0700 Subject: [PATCH 077/234] adds rewards --- .../behavior/data_objects/rewards.py | 81 ++++++++++++++++++ .../data_objects/test_data/rewards.pkl | Bin 0 -> 2304 bytes .../behavior/data_objects/test_rewards.py | 61 +++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 allensdk/brain_observatory/behavior/data_objects/rewards.py create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_data/rewards.pkl create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_rewards.py diff --git a/allensdk/brain_observatory/behavior/data_objects/rewards.py b/allensdk/brain_observatory/behavior/data_objects/rewards.py new file mode 100644 index 000000000..7b3ac55f6 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/rewards.py @@ -0,0 +1,81 @@ +import pandas as pd +from pynwb import NWBFile, TimeSeries, ProcessingModule + +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects import DataObject, \ + StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + StimulusFileReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .writable_interfaces import \ + NwbWritableInterface + + +class Rewards(DataObject, StimulusFileReadableInterface, NwbReadableInterface, + NwbWritableInterface): + def __init__(self, rewards: pd.DataFrame): + super().__init__(name='rewards', value=rewards) + + @classmethod + def from_stimulus_file(cls, stimulus_file: StimulusFile) -> "Rewards": + """Get reward data from pkl file, based on pkl file timestamps + (not sync file). + """ + data = stimulus_file.data + timestamps = StimulusTimestamps.from_stimulus_file( + stimulus_file=stimulus_file) + + trial_df = pd.DataFrame(data["items"]["behavior"]["trial_log"]) + rewards_dict = {"volume": [], "timestamps": [], "autorewarded": []} + for idx, trial in trial_df.iterrows(): + rewards = trial["rewards"] + # as i write this there can only ever be one reward per trial + if rewards: + rewards_dict["volume"].append(rewards[0][0]) + rewards_dict["timestamps"].append( + timestamps.value[rewards[0][2]]) + auto_rwrd = trial["trial_params"]["auto_reward"] + rewards_dict["autorewarded"].append(auto_rwrd) + + df = pd.DataFrame(rewards_dict) + return cls(rewards=df) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "Rewards": + if 'rewards' in nwbfile.processing: + rewards = nwbfile.processing['rewards'] + time = rewards.get_data_interface('autorewarded').timestamps[:] + autorewarded = rewards.get_data_interface('autorewarded').data[:] + volume = rewards.get_data_interface('volume').data[:] + df = pd.DataFrame({ + 'volume': volume, 'timestamps': time, + 'autorewarded': autorewarded}) + else: + df = pd.DataFrame({ + 'volume': [], 'timestamps': [], + 'autorewarded': []}) + return cls(rewards=df) + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + reward_volume_ts = TimeSeries( + name='volume', + data=self.value['volume'].values, + timestamps=self.value['timestamps'].values, + unit='mL' + ) + + autorewarded_ts = TimeSeries( + name='autorewarded', + data=self.value['autorewarded'].values, + timestamps=reward_volume_ts.timestamps, + unit='mL' + ) + + rewards_mod = ProcessingModule('rewards', + 'Licking behavior processing module') + rewards_mod.add_data_interface(reward_volume_ts) + rewards_mod.add_data_interface(autorewarded_ts) + nwbfile.add_processing_module(rewards_mod) + + return nwbfile diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_data/rewards.pkl b/allensdk/test/brain_observatory/behavior/data_objects/test_data/rewards.pkl new file mode 100644 index 0000000000000000000000000000000000000000..1b1876db5d7bc36519e7131e9ecce28016d3ce8b GIT binary patch literal 2304 zcmeH}dr;I>6vua$U0G2OQn5`(69pli6%><_G zNPoSFC2133V3bC}L?nWRx0$!TDU&Ceor_ zZo+FgfEvTghHW9UbSUve6K70J9;(yG8CX3*(?l}Pr>04**~G9kr)6w=|H7FNFBVUzR<&=%6iM&k5CMS|Yh-76D_ECw4_MLcfDvFGZjChQPS@B1 zARHAf%p)XIev!NkpG~v4DqhO4=0v255eyO=V#k>zu7;XGO%kM0ieX_ARZI?|rt*^b zX9NX5BS<6&3SA`=iBcx)UwUIR8}e^+@@=00`M%VU7xRmI_&@#!k8i#zI_Sy3AxrQ( zSI#q#rcf31hq7>`xyIe&5)0#7H~ujvmV>V@mA$TKk|5J|&U_%%0;ghHb9&}~E>OXguyS=p)mL;WU4R&q? z#l@G-9<0j(%k}Ox&c9|sRkx=%)shY823B{{5jl_^{mZtZ_8hSJeRDs4O)m6hez7Hj z*ap|u9{=)=IS*#rPoB$g{t%qkCtdYU*$$^4EvW72<{{?CX_E(z=0lTp+y*AK0FnyB zv~hKX(E4+i`+TAZx&mA79^GFA5AIB8+i|}L8YGWGrSZkEEO^T7mX2bm80}`bwzLE; zj9caMwEuxRI}%3X9Bd~b0ZXu4bmLEmcI`q%FO z|HhkC=iG8g==U$^QJ2HjO*ghX@BA3KHt|2Ue%8TySerCG>bIyz<_xge85V z;LIJBuqgYt`RI5hc#jzzFYc^_*zaPU@~W$#nm+uf?DHzvy(s-VZ4@5b!bI#(-P zN|`JPudu?N<%{Jtfz@!=^QU?I<{DV6sGj1UUjs4Wy4x+*8i>8n-raks25g(ojFo59 z!YO-ZGeWgM+w)5MBI+SH%I`svt{!Y`)L!@edU(TYSzpi1da%cxT{mq;1N7c|VV%=dIY%D%3pXb&Hs}_d2AGy;A^Ut4{!QF3!T?<=| zaNhgi`ezLufvg?QC;OM5+-?ViU)JXzX7TXDtO*!N8p`Ww&N!asuo$s0h5-HFeTBjt z)NrN7VXjgh&sQnIESWBFj`F5_1dL%4Jt5dX#)zN9P_u{;0c0BDNBJuQ0+j)d_CZQu z+#||`AEgo60|wzFxCqQs!oUeTLA>0UK&$a4=BZr6=`rC=*px8_y;guU=Cfpo(40^` qNrh4Ilpe1+Jy|6=1{c6f)tKtIhY`Al;eJMKBw51IM#Ldbqx=hXm#qE( literal 0 HcmV?d00001 diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_rewards.py b/allensdk/test/brain_observatory/behavior/data_objects/test_rewards.py new file mode 100644 index 000000000..100635e5d --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/test_rewards.py @@ -0,0 +1,61 @@ +from datetime import datetime +from pathlib import Path + +import pandas as pd +import pynwb +import pytest + +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects.rewards import Rewards +from allensdk.test.brain_observatory.behavior.data_objects.lims_util import \ + LimsTest + + +class TestFromStimulusFile(LimsTest): + @classmethod + def setup_class(cls): + cls.behavior_session_id = 994174745 + + dir = Path(__file__).parent.resolve() + test_data_dir = dir / 'test_data' + + expected = pd.read_pickle(str(test_data_dir / 'rewards.pkl')) + cls.expected = Rewards(rewards=expected) + + @pytest.mark.requires_bamboo + def test_from_stimulus_file(self): + self.stimulus_file = StimulusFile.from_lims( + behavior_session_id=self.behavior_session_id, db=self.dbconn) + rewards = Rewards.from_stimulus_file(stimulus_file=self.stimulus_file) + assert rewards == self.expected + + +class TestNWB: + @classmethod + def setup_class(cls): + dir = Path(__file__).parent.resolve() + test_data_dir = dir / 'test_data' + + rewards = pd.read_pickle(str(test_data_dir / 'rewards.pkl')) + cls.rewards = Rewards(rewards=rewards) + + def setup_method(self, method): + self.nwbfile = pynwb.NWBFile( + session_description='asession', + identifier='1234', + session_start_time=datetime.now() + ) + + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_read_write_nwb(self, roundtrip, + data_object_roundtrip_fixture): + self.rewards.to_nwb(nwbfile=self.nwbfile) + + if roundtrip: + obt = data_object_roundtrip_fixture( + nwbfile=self.nwbfile, + data_object_cls=Rewards) + else: + obt = self.rewards.from_nwb(nwbfile=self.nwbfile) + + assert obt == self.rewards From 6fae811999fba0f570fd598c81528d9e7b60a8e9 Mon Sep 17 00:00:00 2001 From: aamster Date: Thu, 15 Jul 2021 06:21:23 -0700 Subject: [PATCH 078/234] remove unused var --- .../metadata/behavior_metadata/behavior_metadata.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py index 956968d9a..18276b339 100644 --- a/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/data_objects/metadata/behavior_metadata/behavior_metadata.py @@ -217,8 +217,6 @@ def from_internal( stimulus_file = StimulusFile.from_lims( db=lims_db, behavior_session_id=behavior_session_id.value) - stimulus_timestamps = StimulusTimestamps.from_stimulus_file( - stimulus_file=stimulus_file) stimulus_frame_rate = StimulusFrameRate.from_stimulus_file( stimulus_file=stimulus_file) session_type = SessionType.from_stimulus_file( @@ -254,8 +252,6 @@ def from_json(cls, dict_repr: dict) -> "BehaviorMetadata": date_of_acquisition = DateOfAcquisition.from_json(dict_repr=dict_repr) stimulus_file = StimulusFile.from_json(dict_repr=dict_repr) - stimulus_timestamps = StimulusTimestamps.from_stimulus_file( - stimulus_file=stimulus_file) stimulus_frame_rate = StimulusFrameRate.from_stimulus_file( stimulus_file=stimulus_file) session_type = SessionType.from_stimulus_file( From e83dca820108649ac4bcb3222a749d597358d3b5 Mon Sep 17 00:00:00 2001 From: aamster Date: Thu, 15 Jul 2021 06:21:36 -0700 Subject: [PATCH 079/234] adds trials --- .../behavior/data_objects/trials/__init__.py | 0 .../behavior/data_objects/trials/trial.py | 422 ++++++++++++++++++ .../behavior/data_objects/trials/trials.py | 192 ++++++++ .../data_objects/test_data/trials.pkl | Bin 0 -> 78578 bytes .../behavior/data_objects/test_trials.py | 85 ++++ 5 files changed, 699 insertions(+) create mode 100644 allensdk/brain_observatory/behavior/data_objects/trials/__init__.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/trials/trial.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/trials/trials.py create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_data/trials.pkl create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_trials.py diff --git a/allensdk/brain_observatory/behavior/data_objects/trials/__init__.py b/allensdk/brain_observatory/behavior/data_objects/trials/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_objects/trials/trial.py b/allensdk/brain_observatory/behavior/data_objects/trials/trial.py new file mode 100644 index 000000000..1e3781cee --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/trials/trial.py @@ -0,0 +1,422 @@ +from typing import List, Dict + +import numpy as np + +from allensdk import one +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects import StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects.licks import Licks +from allensdk.brain_observatory.behavior.data_objects.rewards import Rewards + + +class Trial: + def __init__(self, trial: dict, start: float, end: float, + behavior_stimulus_file: StimulusFile, + index: int, monitor_delay: float, + stimulus_timestamps: StimulusTimestamps, + licks: Licks, rewards: Rewards, stimuli: dict): + self._trial = trial + self._start = start + self._end = self._calculate_trial_end( + trial_end=end, behavior_stimulus_file=behavior_stimulus_file) + self._index = index + self._data = self._match_to_sync_timestamps( + monitor_delay=monitor_delay, + stimulus_timestamps=stimulus_timestamps, licks=licks, + rewards=rewards, stimuli=stimuli) + + @property + def data(self): + return self._data + + def _match_to_sync_timestamps( + self, monitor_delay: float, + stimulus_timestamps: StimulusTimestamps, + licks: Licks, rewards: Rewards, + stimuli: dict): + event_dict = { + (e[0], e[1]): { + 'timestamp': stimulus_timestamps.value[e[3]], + 'frame': e[3]} for e in self._trial['events'] + } + + tr_data = {"trial": self._trial["index"]} + lick_frames = licks.value['frame'].values + timestamps = stimulus_timestamps.value + reward_times = rewards.value['timestamps'].values + + # this block of code is trying to mimic + # https://github.com/AllenInstitute/visual_behavior_analysis + # /blob/master/visual_behavior/translator/foraging2/__init__.py + # #L377-L381 + # https://github.com/AllenInstitute/visual_behavior_analysis + # /blob/master/visual_behavior/translator/foraging2 + # /extract_movies.py#L59-L94 + # https://github.com/AllenInstitute/visual_behavior_analysis + # /blob/master/visual_behavior/translator/core/annotate.py#L11-L36 + # + # In summary: there are cases where an "epilogue movie" is shown + # after the proper stimuli; we do not want licks that occur + # during this epilogue movie to be counted as belonging to + # the last trial + # https://github.com/AllenInstitute/visual_behavior_analysis + # /issues/482 + + # select licks that fall between trial_start and trial_end; + # licks on the boundary get assigned to the trial that is ending, + # rather than the trial that is starting + if self._end > 0: + valid_idx = np.where(np.logical_and(lick_frames > self._start, + lick_frames <= self._end)) + else: + valid_idx = np.where(lick_frames > self._start) + + valid_licks = lick_frames[valid_idx] + if len(valid_licks) > 0: + tr_data["lick_times"] = timestamps[valid_licks] + else: + tr_data["lick_times"] = np.array([], dtype=float) + + tr_data["reward_time"] = self._get_reward_time( + reward_times, + event_dict[('trial_start', '')]['timestamp'], + event_dict[('trial_end', '')]['timestamp'] + ) + tr_data.update(self._get_trial_data()) + tr_data.update(self._get_trial_timing( + event_dict, + tr_data['lick_times'], + tr_data['go'], + tr_data['catch'], + tr_data['auto_rewarded'], + tr_data['hit'], + tr_data['false_alarm'], + tr_data["aborted"], + timestamps, + monitor_delay + )) + tr_data.update(self._get_trial_image_names(stimuli)) + + self._validate_trial_condition_exclusivity(tr_data=tr_data) + + return tr_data + + @staticmethod + def _get_reward_time(rebased_reward_times, + start_time, + stop_time): + """extract reward times in time range""" + reward_times = rebased_reward_times[np.where(np.logical_and( + rebased_reward_times >= start_time, + rebased_reward_times <= stop_time + ))] + return float('nan') if len(reward_times) == 0 else one( + reward_times) + + @staticmethod + def _calculate_trial_end(trial_end, + behavior_stimulus_file: StimulusFile): + if trial_end < 0: + bhv = behavior_stimulus_file.data['items']['behavior']['items'] + if 'fingerprint' in bhv.keys(): + trial_end = bhv['fingerprint']['starting_frame'] + return trial_end + + def _get_trial_data(self): + """ + Infer trial logic from trial log. Returns a dictionary. + + * reward volume: volume of water delivered on the trial, in mL + + Each of the following values is boolean: + + Trial category values are mutually exclusive + * go: trial was a go trial (trial with a stimulus change) + * catch: trial was a catch trial (trial with a sham stimulus change) + + stimulus_change/sham_change are mutually exclusive + * stimulus_change: did the stimulus change (True on 'go' trials) + * sham_change: stimulus did not change, but response was evaluated + (True on 'catch' trials) + + Each trial can be one (and only one) of the following: + * hit (stimulus changed, animal responded in response window) + * miss (stimulus changed, animal did not respond in response window) + * false_alarm (stimulus did not change, + animal responded in response window) + * correct_reject (stimulus did not change, + animal did not respond in response window) + * aborted (animal responded before change time) + * auto_rewarded (reward was automatically delivered following the + change. + This will bias the animals choice and should not be + categorized as hit/miss) + """ + trial_event_names = [val[0] for val in self._trial['events']] + hit = 'hit' in trial_event_names + false_alarm = 'false_alarm' in trial_event_names + miss = 'miss' in trial_event_names + sham_change = 'sham_change' in trial_event_names + stimulus_change = 'stimulus_changed' in trial_event_names + aborted = 'abort' in trial_event_names + + if aborted: + go = catch = auto_rewarded = False + else: + catch = self._trial["trial_params"]["catch"] is True + auto_rewarded = self._trial["trial_params"]["auto_reward"] + go = not catch and not auto_rewarded + + correct_reject = catch and not false_alarm + + if auto_rewarded: + hit = miss = correct_reject = false_alarm = False + + return { + "reward_volume": sum([ + r[0] for r in self._trial.get("rewards", [])]), + "hit": hit, + "false_alarm": false_alarm, + "miss": miss, + "sham_change": sham_change, + "stimulus_change": stimulus_change, + "aborted": aborted, + "go": go, + "catch": catch, + "auto_rewarded": auto_rewarded, + "correct_reject": correct_reject, + } + + @staticmethod + def _get_trial_timing( + event_dict: dict, + licks: List[float], go: bool, catch: bool, auto_rewarded: bool, + hit: bool, false_alarm: bool, aborted: bool, + timestamps: np.ndarray, + monitor_delay: float): + """ + Extract a dictionary of trial timing data. + See trial_data_from_log for a description of the trial types. + + Parameters + ========== + event_dict: dict + Dictionary of trial events in the well-known `pkl` file + licks: List[float] + list of lick timestamps, from the `get_licks` response for + the BehaviorOphysExperiment.api. + go: bool + True if "go" trial, False otherwise. Mutually exclusive with + `catch`. + catch: bool + True if "catch" trial, False otherwise. Mutually exclusive + with `go.` + auto_rewarded: bool + True if "auto_rewarded" trial, False otherwise. + hit: bool + True if "hit" trial, False otherwise + false_alarm: bool + True if "false_alarm" trial, False otherwise + aborted: bool + True if "aborted" trial, False otherwise + timestamps: np.ndarray[1d] + Array of ground truth timestamps for the session + (sync times, if available) + monitor_delay: float + The monitor delay in seconds associated with the session + + Returns + ======= + dict + start_time: float + The time the trial started (in seconds elapsed from + recording start) + stop_time: float + The time the trial ended (in seconds elapsed from + recording start) + trial_length: float + Duration of the trial in seconds + response_time: float + The response time, for non-aborted trials. This is equal + to the first lick in the trial. For aborted trials or trials + without licks, `response_time` is NaN. + change_frame: int + The frame number that the stimulus changed + change_time: float + The time in seconds that the stimulus changed + response_latency: float or None + The time in seconds between the stimulus change and the + animal's lick response, if the trial is a "go", "catch", or + "auto_rewarded" type. If the animal did not respond, + return `float("inf")`. In all other cases, return None. + + Notes + ===== + The following parameters are mutually exclusive (exactly one can + be true): + hit, miss, false_alarm, aborted, auto_rewarded + """ + assert not (aborted and (hit or false_alarm or auto_rewarded)), ( + "'aborted' trials cannot be 'hit', 'false_alarm', " + "or 'auto_rewarded'") + assert not (hit and false_alarm), ( + "both `hit` and `false_alarm` cannot be True, they are mutually " + "exclusive categories") + assert not (go and catch), ( + "both `go` and `catch` cannot be True, they are mutually " + "exclusive " + "categories") + assert not (go and auto_rewarded), ( + "both `go` and `auto_rewarded` cannot be True, they are mutually " + "exclusive categories") + + def _get_response_time(licks: List[float], aborted: bool) -> float: + """ + Return the time the first lick occurred in a non-"aborted" trial. + A response time is not returned for on an "aborted trial", since by + definition, the animal licked before the change stimulus. + """ + if aborted: + return float("nan") + if len(licks): + return licks[0] + else: + return float("nan") + + start_time = event_dict["trial_start", ""]['timestamp'] + stop_time = event_dict["trial_end", ""]['timestamp'] + + response_time = _get_response_time(licks, aborted) + + if go or auto_rewarded: + change_frame = event_dict.get(('stimulus_changed', ''))['frame'] + change_time = timestamps[change_frame] + monitor_delay + elif catch: + change_frame = event_dict.get(('sham_change', ''))['frame'] + change_time = timestamps[change_frame] + monitor_delay + else: + change_time = float("nan") + change_frame = float("nan") + + if not (go or catch or auto_rewarded): + response_latency = None + elif len(licks) > 0: + response_latency = licks[0] - change_time + else: + response_latency = float("inf") + + return { + "start_time": start_time, + "stop_time": stop_time, + "trial_length": stop_time - start_time, + "response_time": response_time, + "change_frame": change_frame, + "change_time": change_time, + "response_latency": response_latency, + } + + def _get_trial_image_names(self, stimuli) -> Dict[str, str]: + """ + Gets the name of the stimulus presented at the beginning of the + trial and + what is it changed to at the end of the trial. + Parameters + ---------- + stimuli: The stimuli presentation log for the behavior session + + Returns + ------- + A dictionary indicating the starting_stimulus and what the + stimulus is + changed to. + + """ + grating_oris = {'horizontal', 'vertical'} + trial_start_frame = self._trial["events"][0][3] + initial_image_category_name, _, initial_image_name = \ + self._resolve_initial_image( + stimuli, trial_start_frame) + if len(self._trial["stimulus_changes"]) == 0: + change_image_name = initial_image_name + else: + ((from_set, from_name), + (to_set, to_name), + _, _) = self._trial["stimulus_changes"][0] + + # do this to fix names if the stimuli is a grating + if from_set in grating_oris: + from_name = f'gratings_{from_name}' + if to_set in grating_oris: + to_name = f'gratings_{to_name}' + assert from_name == initial_image_name + change_image_name = to_name + + return { + "initial_image_name": initial_image_name, + "change_image_name": change_image_name + } + + @staticmethod + def _resolve_initial_image(stimuli, start_frame): + """Attempts to resolve the initial image for a given start_frame for + a trial + + Parameters + ---------- + stimuli: Mapping + foraging2 shape stimuli mapping + start_frame: int + start frame of the trial + + Returns + ------- + initial_image_category_name: str + stimulus category of initial image + initial_image_group: str + group name of the initial image + initial_image_name: str + name of the initial image + """ + max_frame = float("-inf") + initial_image_group = '' + initial_image_name = '' + initial_image_category_name = '' + + for stim_category_name, stim_dict in stimuli.items(): + for set_event in stim_dict["set_log"]: + set_frame = set_event[3] + if start_frame >= set_frame >= max_frame: + # hack assumes initial_image_group == initial_image_name, + # only initial_image_name is present for natual_scenes + initial_image_group = initial_image_name = set_event[1] + initial_image_category_name = stim_category_name + if initial_image_category_name == 'grating': + initial_image_name = f'gratings_{initial_image_name}' + max_frame = set_frame + + return initial_image_category_name, initial_image_group, \ + initial_image_name + + def _validate_trial_condition_exclusivity(self, tr_data: dict): + """ensure that only one of N possible mutually + exclusive trial conditions is True""" + trial_conditions = {} + for key in ['hit', + 'miss', + 'false_alarm', + 'correct_reject', + 'auto_rewarded', + 'aborted']: + trial_conditions[key] = tr_data[key] + + on = [] + for condition, value in trial_conditions.items(): + if value: + on.append(condition) + + if len(on) != 1: + all_conditions = list(trial_conditions.keys()) + msg = f"expected exactly 1 trial condition out of " \ + f"{all_conditions} " + msg += f"to be True, instead {on} were True (trial {self._index})" + raise AssertionError(msg) \ No newline at end of file diff --git a/allensdk/brain_observatory/behavior/data_objects/trials/trials.py b/allensdk/brain_observatory/behavior/data_objects/trials/trials.py new file mode 100644 index 000000000..a323a7a00 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/trials/trials.py @@ -0,0 +1,192 @@ +import warnings +from typing import Optional, List + +import pandas as pd +from pynwb import NWBFile + +from allensdk.brain_observatory import dict_to_indexed_array +from allensdk.brain_observatory.behavior.data_files import StimulusFile, \ + SyncFile +from allensdk.brain_observatory.behavior.data_objects import DataObject, \ + StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + StimulusFileReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .writable_interfaces import \ + NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.licks import Licks +from allensdk.brain_observatory.behavior.data_objects.metadata \ + .behavior_metadata.equipment import \ + Equipment +from allensdk.brain_observatory.behavior.data_objects.rewards import Rewards +from allensdk.brain_observatory.behavior.data_objects.trials.trial import Trial +from allensdk.internal.brain_observatory.time_sync import OphysTimeAligner + + +class Trials(DataObject, StimulusFileReadableInterface, NwbReadableInterface, + NwbWritableInterface): + def __init__(self, trials: pd.DataFrame): + super().__init__(name='trials', value=trials) + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + trials = self.value + order = list(trials.index) + for _, row in trials[['start_time', 'stop_time']].iterrows(): + row_dict = row.to_dict() + nwbfile.add_trial(**row_dict) + + for c in trials.columns: + if c in ['start_time', 'stop_time']: + continue + index, data = dict_to_indexed_array(trials[c].to_dict(), order) + if data.dtype == ' "Trials": + trials = nwbfile.trials.to_dataframe() + if 'lick_events' in trials.columns: + trials.drop('lick_events', inplace=True, axis=1) + trials.index = trials.index.rename('trials_id') + return Trials(trials=trials) + + @classmethod + def from_stimulus_file(cls, stimulus_file: StimulusFile, + stimulus_timestamps: StimulusTimestamps, + licks: Licks, + rewards: Rewards, + monitor_delay: Optional[float] = None, + sync_file: Optional[SyncFile] = None, + equipment: Optional[Equipment] = None + ) -> "Trials": + if monitor_delay is None: + if sync_file is None or equipment is None: + raise ValueError('Need sync file and equipment in order to ' + 'calculate monitor delay') + monitor_delay = cls._calculate_monitor_delay(sync_file=sync_file, + equipment=equipment) + bsf = stimulus_file.data + + stimuli = bsf["items"]["behavior"]["stimuli"] + trial_log = bsf["items"]["behavior"]["trial_log"] + + trial_bounds = cls._get_trial_bounds(trial_log=trial_log) + + all_trial_data = [None] * len(trial_log) + + for idx, trial in enumerate(trial_log): + trial_start, trial_end = trial_bounds[idx] + t = Trial(trial=trial, start=trial_start, end=trial_end, + behavior_stimulus_file=stimulus_file, + index=idx, + monitor_delay=monitor_delay, + stimulus_timestamps=stimulus_timestamps, + licks=licks, rewards=rewards, + stimuli=stimuli + ) + all_trial_data[idx] = t.data + + trials = pd.DataFrame(all_trial_data).set_index('trial') + trials.index = trials.index.rename('trials_id') + del trials["sham_change"] + + return Trials(trials=trials) + + @staticmethod + def _calculate_monitor_delay(sync_file: SyncFile, + equipment: Equipment): + aligner = OphysTimeAligner(sync_file=sync_file.filepath) + + try: + delay = aligner.monitor_delay + except ValueError as ee: + equipment_name = equipment.value + + warning_msg = 'Monitory delay calculation failed ' + warning_msg += 'with ValueError\n' + warning_msg += f' "{ee}"' + warning_msg += '\nlooking monitor delay up from table ' + warning_msg += f'for rig: {equipment_name} ' + + # see + # https://github.com/AllenInstitute/AllenSDK/issues/1318 + # https://github.com/AllenInstitute/AllenSDK/issues/1916 + delay_lookup = {'CAM2P.1': 0.020842, + 'CAM2P.2': 0.037566, + 'CAM2P.3': 0.021390, + 'CAM2P.4': 0.021102, + 'CAM2P.5': 0.021192, + 'MESO.1': 0.03613} + + if equipment_name not in delay_lookup: + msg = warning_msg + msg += f'\nequipment_name {equipment_name} not in lookup table' + raise RuntimeError(msg) + delay = delay_lookup[equipment_name] + warning_msg += f'\ndelay: {delay} seconds' + warnings.warn(warning_msg) + + return delay + + @staticmethod + def _get_trial_bounds(trial_log: List) -> List: + """ + Adjust trial boundaries from a trial_log so that there is no dead time + between trials. + + Parameters + ---------- + trial_log: list + The trial_log read in from the well known behavior stimulus + pickle file + + Returns + ------- + list + Each element in the list is a tuple of the form + (start_frame, end_frame) so that the ith element + of the list gives the start and end frames of + the ith trial. The endframe of the last trial will + be -1, indicating that it should map to the last + timestamp in the session + """ + start_frames = [] + + for trial in trial_log: + start_f = None + for event in trial['events']: + if event[0] == 'trial_start': + start_f = event[-1] + break + if start_f is None: + msg = "Could not find a 'trial_start' event " + msg += "for all trials in the trial log\n" + msg += f"{trial}" + raise ValueError(msg) + + if len(start_frames) > 0 and start_f < start_frames[-1]: + msg = "'trial_start' frames in trial log " + msg += "are not in ascending order" + msg += f"\ntrial_log: {trial_log}" + raise ValueError(msg) + + start_frames.append(start_f) + + end_frames = [idx for idx in start_frames[1:] + [-1]] + return list([(s, e) for s, e in zip(start_frames, end_frames)]) diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_data/trials.pkl b/allensdk/test/brain_observatory/behavior/data_objects/test_data/trials.pkl new file mode 100644 index 0000000000000000000000000000000000000000..8a87d8a2d99751175c66db5198f0eceec0533b63 GIT binary patch literal 78578 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 !E&1sBtaGG>FK zO;=D(dntclnry2(0q{=`hnCP5~(;iKO5}L=8Bw0 z()G9Jv9n~uf%HwhPRPl}pIFN~gH|or!bwSM%9If%el#r_2$KFI6I0s%KO`jH8!E3; zV7l-w8>$N{UwuXzUvZ*yeV+{rzw>F8BRLXH*0X%b2LB;Ne+^{2WJ-N3GC$zWl}_YW z%WW&7f4o~dTdHU69pwM%Zxzd=quXNdPkV)t%vTMpq2J5d!^ zhcqZw*sS|48~U!E<~oNwBg|(06-g(xd-ulSY!KP5ClH9_3A_~6f-Ei`{3bP$4YG^N zyCRT_K257?LDnn}7hV4yS3tMW%1C7ATd%nRgIu?ZQs+PvdL~T{M73LPJBeJPq#*qOIeB!%jnXG7 zbA$A>9I!o&`_CXJ*CrcaKd?K>&OL}T=@TENK!VGgxkB z$8GASRP>Ur%#ndE@k6rC=Fw-z&CIhiUFDxJjnSF8d^M#^F_DVS2?9~fN+D)$Wm=l0 zeTdK`$S7!iDX{1LopW}Lw{w>C<$mt_xvu-VulqSpWIEHoSNC>Q>^b>z+}S+rnY|UU zxO1-Wu`f>Ab8hM6lDw|CbFjR>ZN5Egr@h&;&7Qyge(vC9dmg>=&Bn5Aac9C0$DfSa z^Ns7XKJB&Vp0EG7qwtlub9Q%PWUD>5tRC@KuRSL%K6bHqyVdP6eNlVPzVcZ`pFNAd znsB0|JMMfr|GmQ-yfeRc;(2@SpOYIae>Lu0{r-jP8|*oyVb_*F?RoG*&qMV)?B{;I z`2Bb6nfVRUf7Se9(}mY>b?vW$!rrcsJ+IEq8}+$8gV!6jR_%;CkDULcW4k>Mg*UJK z)t+0<9KKe+EABj8vhceP?AhF0aJuNVxO3{p*<-8hnR#0J)2z9F?vaZJ;?9A<`u?eJ zWn&NdwUGYsp1;snpL;5sM0#NOL~W$$Qrx-LK7PTz%h}jN4jd9pyE%R1m(JSaM3(i3 zl=%N(ddb!e{cpecc*5EEPh?}KpP{HLu(o$`Hdgw3x<`9{?%uR4;r!hlSaRH+4~%|r)1Au`&W^oLP5;Pb z>mKw@u@TL!71cA{aAZ_YPO_NohTCjGNZw3$lV_zHZXcjkyWzDS&1+QmEGxAx-7Sfl znv_J98;*MLvjYJUTF5#)0176&c?=!YpAfeeUjdohRT5XvS@Q0qJk%hFm z4v<1wPU+ALb!a0fw1H|a06`9*P--nGj3fY%XEBcbY+|wJ1^1(qsTqfkFw20GX6U1|@*fOJErQk+~zF2ahdrKt_jnP#|XtG6au7 z>eV0sl;IK7D}UVSvy?SDv?X>4QXylcZyDr~g2En1!J{ODM+Qm&MHB%jc#%m^l<5F~ zf)pqK83KsHBO}m3fJX*d3yKV&KnKCMkxb$MDU{`u4$V-9HiAMMsOAC?gQ~n;B-NsWvrUx4CaYbgR42 zy(xt7mrjGP4JFh1R>Vyox~Oj6kJpH;4@nt_ww6 zGb)zX*z$DK%7|;7d-r+m!Ir3pEQ*b6U9qOYg0{%G?Yz!8^Kz3v_mOi;>KvUq3sUEp z)LEE1i&E#<)OlO#^u9+Kwe!RK>}#8);r;fAjcklIx3o2{irDYFMOvDhLhcT?Zdl#u zy4;uSONzb%`oB$j&tXlDPtC}=J(Y|bJTw%I*x9k+4Q(B(-B|vzU|VqcnqX_l<_)c( NwxD-mA1B%v_y@gOW?cXP literal 0 HcmV?d00001 diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_trials.py b/allensdk/test/brain_observatory/behavior/data_objects/test_trials.py new file mode 100644 index 000000000..4bc1d049c --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/data_objects/test_trials.py @@ -0,0 +1,85 @@ +from datetime import datetime +from pathlib import Path + +import pandas as pd +import pynwb +import pytest + +from allensdk.brain_observatory.behavior.data_files import StimulusFile, \ + SyncFile +from allensdk.brain_observatory.behavior.data_objects import StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects.licks import Licks +from allensdk.brain_observatory.behavior.data_objects.metadata\ + .behavior_metadata.equipment import \ + Equipment +from allensdk.brain_observatory.behavior.data_objects.rewards import Rewards +from allensdk.brain_observatory.behavior.data_objects.trials.trials import \ + Trials +from allensdk.test.brain_observatory.behavior.data_objects.lims_util import \ + LimsTest + + +class TestFromStimulusFile(LimsTest): + @classmethod + def setup_class(cls): + cls.behavior_session_id = 994174745 + cls.ophys_experiment_id = 994278291 + + dir = Path(__file__).parent.resolve() + test_data_dir = dir / 'test_data' + + expected = pd.read_pickle(str(test_data_dir / 'trials.pkl')) + cls.expected = Trials(trials=expected) + + @pytest.mark.requires_bamboo + def test_from_stimulus_file(self): + stimulus_file = StimulusFile.from_lims( + behavior_session_id=self.behavior_session_id, db=self.dbconn) + stimulus_timestamps = StimulusTimestamps.from_stimulus_file( + stimulus_file=stimulus_file) + licks = Licks.from_stimulus_file(stimulus_file=stimulus_file) + rewards = Rewards.from_stimulus_file(stimulus_file=stimulus_file) + sync_file = SyncFile.from_lims( + db=self.dbconn, ophys_experiment_id=self.ophys_experiment_id) + equipment = Equipment.from_lims( + behavior_session_id=self.behavior_session_id, lims_db=self.dbconn) + trials = Trials.from_stimulus_file( + stimulus_file=stimulus_file, + stimulus_timestamps=stimulus_timestamps, + licks=licks, + rewards=rewards, + sync_file=sync_file, + equipment=equipment + ) + assert trials == self.expected + + +class TestNWB: + @classmethod + def setup_class(cls): + dir = Path(__file__).parent.resolve() + test_data_dir = dir / 'test_data' + + trials = pd.read_pickle(str(test_data_dir / 'trials.pkl')) + cls.trials = Trials(trials=trials) + + def setup_method(self, method): + self.nwbfile = pynwb.NWBFile( + session_description='asession', + identifier='1234', + session_start_time=datetime.now() + ) + + @pytest.mark.parametrize('roundtrip', [True, False]) + def test_read_write_nwb(self, roundtrip, + data_object_roundtrip_fixture): + self.trials.to_nwb(nwbfile=self.nwbfile) + + if roundtrip: + obt = data_object_roundtrip_fixture( + nwbfile=self.nwbfile, + data_object_cls=Trials) + else: + obt = self.trials.from_nwb(nwbfile=self.nwbfile) + + assert obt == self.trials From da5d1441ad5692c375bd5735086fba0caf291bbb Mon Sep 17 00:00:00 2001 From: aamster Date: Fri, 16 Jul 2021 07:18:25 -0700 Subject: [PATCH 080/234] add stimuli --- .../behavior/data_objects/stimuli/__init__.py | 0 .../data_objects/stimuli/presentations.py | 153 ++++++++++++++++++ .../behavior/data_objects/stimuli/stimuli.py | 58 +++++++ .../stimuli/stimulus_processing.py} | 25 ++- .../stimuli}/stimulus_templates.py | 2 +- .../data_objects/stimuli/templates.py | 145 +++++++++++++++++ .../stimuli}/util.py | 0 .../behavior/data_objects/trials/trial.py | 2 +- .../abcs/session_base/behavior_base.py | 4 +- .../behavior_data_transforms.py | 7 +- allensdk/brain_observatory/nwb/__init__.py | 3 +- .../brain_observatory/behavior/conftest.py | 4 +- .../data_objects/test_data/presentations.pkl | Bin 0 -> 42107 bytes .../data_objects/test_data/templates.pkl | Bin 0 -> 20736642 bytes .../behavior/data_objects/test_stimuli.py | 98 +++++++++++ .../behavior/test_stimulus_processing.py | 2 +- 16 files changed, 485 insertions(+), 18 deletions(-) create mode 100644 allensdk/brain_observatory/behavior/data_objects/stimuli/__init__.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/stimuli/presentations.py create mode 100644 allensdk/brain_observatory/behavior/data_objects/stimuli/stimuli.py rename allensdk/brain_observatory/behavior/{stimulus_processing/__init__.py => data_objects/stimuli/stimulus_processing.py} (95%) rename allensdk/brain_observatory/behavior/{stimulus_processing => data_objects/stimuli}/stimulus_templates.py (99%) create mode 100644 allensdk/brain_observatory/behavior/data_objects/stimuli/templates.py rename allensdk/brain_observatory/behavior/{stimulus_processing => data_objects/stimuli}/util.py (100%) create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_data/presentations.pkl create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_data/templates.pkl create mode 100644 allensdk/test/brain_observatory/behavior/data_objects/test_stimuli.py diff --git a/allensdk/brain_observatory/behavior/data_objects/stimuli/__init__.py b/allensdk/brain_observatory/behavior/data_objects/stimuli/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/allensdk/brain_observatory/behavior/data_objects/stimuli/presentations.py b/allensdk/brain_observatory/behavior/data_objects/stimuli/presentations.py new file mode 100644 index 000000000..2cc81a504 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/stimuli/presentations.py @@ -0,0 +1,153 @@ +from typing import Optional, List + +import pandas as pd +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects import DataObject, \ + StimulusTimestamps +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + StimulusFileReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .writable_interfaces import \ + NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.stimuli \ + .stimulus_processing import \ + get_stimulus_presentations, get_stimulus_metadata, is_change_event +from allensdk.brain_observatory.nwb import \ + create_stimulus_presentation_time_interval, get_column_name +from allensdk.brain_observatory.nwb.nwb_api import NwbApi + + +class Presentations(DataObject, StimulusFileReadableInterface, + NwbReadableInterface, NwbWritableInterface): + def __init__(self, presentations: pd.DataFrame): + super().__init__(name='presentations', value=presentations) + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + """Adds a stimulus table (defining stimulus characteristics for each + time point in a session) to an nwbfile as TimeIntervals. + """ + stimulus_table = self.value.copy() + ts = nwbfile.processing['stimulus'].get_data_interface('timestamps') + possible_names = {'stimulus_name', 'image_name'} + stimulus_name_column = get_column_name(stimulus_table.columns, + possible_names) + stimulus_names = stimulus_table[stimulus_name_column].unique() + + for stim_name in sorted(stimulus_names): + specific_stimulus_table = stimulus_table[stimulus_table[ + stimulus_name_column] == stim_name] # noqa: E501 + # Drop columns where all values in column are NaN + cleaned_table = specific_stimulus_table.dropna(axis=1, how='all') + # For columns with mixed strings and NaNs, fill NaNs with 'N/A' + for colname, series in cleaned_table.items(): + types = set(series.map(type)) + if len(types) > 1 and str in types: + series.fillna('N/A', inplace=True) + cleaned_table[colname] = series.transform(str) + + interval_description = (f"Presentation times and stimuli details " + f"for '{stim_name}' stimuli. " + f"\n" + f"Note: image_name references " + f"control_description in " + f"stimulus/templates") + presentation_interval = create_stimulus_presentation_time_interval( + name=f"{stim_name}_presentations", + description=interval_description, + columns_to_add=cleaned_table.columns + ) + + for row in cleaned_table.itertuples(index=False): + row = row._asdict() + + presentation_interval.add_interval( + **row, tags='stimulus_time_interval', timeseries=ts) + + nwbfile.add_time_intervals(presentation_interval) + + return nwbfile + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "Presentations": + # Note: using NwbApi class because ecephys uses this method + # TODO figure out how behavior and ecephys can share this method + nwbapi = NwbApi.from_nwbfile(nwbfile=nwbfile) + df = nwbapi.get_stimulus_presentations() + + df['is_change'] = is_change_event(stimulus_presentations=df) + return Presentations(presentations=df) + + @classmethod + def from_stimulus_file( + cls,stimulus_file: StimulusFile, + limit_to_images: Optional[List] = None) -> "Presentations": + """Get stimulus presentation data. + + NOTE: Uses timestamps that do not account for monitor delay. + + :param limit_to_images + Only return images given by these image names + + :returns: pd.DataFrame -- + Table whose rows are stimulus presentations + (i.e. a given image, for a given duration, typically 250 ms) + and whose columns are presentation characteristics. + """ + stimulus_timestamps = StimulusTimestamps.from_stimulus_file( + stimulus_file=stimulus_file) + stimulus_timestamps = stimulus_timestamps.value + data = stimulus_file.data + raw_stim_pres_df = get_stimulus_presentations( + data, stimulus_timestamps) + + # Fill in nulls for image_name + # This makes two assumptions: + # 1. Nulls in `image_name` should be "gratings_" + # 2. Gratings are only present (or need to be fixed) when all + # values for `image_name` are null. + if pd.isnull(raw_stim_pres_df["image_name"]).all(): + if ~pd.isnull(raw_stim_pres_df["orientation"]).all(): + raw_stim_pres_df["image_name"] = ( + raw_stim_pres_df["orientation"] + .apply(lambda x: f"gratings_{x}")) + else: + raise ValueError("All values for 'orentation' and 'image_name'" + " are null.") + + stimulus_metadata_df = get_stimulus_metadata(data) + + idx_name = raw_stim_pres_df.index.name + stimulus_index_df = ( + raw_stim_pres_df + .reset_index() + .merge(stimulus_metadata_df.reset_index(), on=["image_name"]) + .set_index(idx_name)) + stimulus_index_df = ( + stimulus_index_df[["image_set", "image_index", "start_time", + "phase", "spatial_frequency"]] + .rename(columns={"start_time": "timestamps"}) + .sort_index() + .set_index("timestamps", drop=True)) + stim_pres_df = raw_stim_pres_df.merge( + stimulus_index_df, left_on="start_time", right_index=True, + how="left") + if len(raw_stim_pres_df) != len(stim_pres_df): + raise ValueError("Length of `stim_pres_df` should not change after" + f" merge; was {len(raw_stim_pres_df)}, now " + f" {len(stim_pres_df)}.") + + stim_pres_df['is_change'] = is_change_event( + stimulus_presentations=stim_pres_df) + + # Sort columns then drop columns which contain only all NaN values + stim_pres_df =\ + stim_pres_df[sorted(stim_pres_df)].dropna(axis=1, how='all') + if limit_to_images is not None: + stim_pres_df = \ + stim_pres_df[stim_pres_df['image_name'].isin(limit_to_images)] + stim_pres_df.index = pd.Int64Index( + range(stim_pres_df.shape[0]), name=stim_pres_df.index.name) + return Presentations(presentations=stim_pres_df) diff --git a/allensdk/brain_observatory/behavior/data_objects/stimuli/stimuli.py b/allensdk/brain_observatory/behavior/data_objects/stimuli/stimuli.py new file mode 100644 index 000000000..81cbfd195 --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/stimuli/stimuli.py @@ -0,0 +1,58 @@ +from typing import Optional, List + +from pynwb import NWBFile + +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + StimulusFileReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .writable_interfaces import \ + NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.stimuli.presentations \ + import \ + Presentations +from allensdk.brain_observatory.behavior.data_objects.stimuli.templates \ + import \ + Templates + + +class Stimuli(DataObject, StimulusFileReadableInterface, + NwbReadableInterface, NwbWritableInterface): + def __init__(self, presentations: Presentations, + templates: Templates): + super().__init__(name='stimuli', value=self) + self._presentations = presentations + self._templates = templates + + @property + def presentations(self) -> Presentations: + return self._presentations + + @property + def templates(self) -> Templates: + return self._templates + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "Stimuli": + p = Presentations.from_nwb(nwbfile=nwbfile) + t = Templates.from_nwb(nwbfile=nwbfile) + return Stimuli(presentations=p, templates=t) + + @classmethod + def from_stimulus_file( + cls, stimulus_file: StimulusFile, + limit_to_images: Optional[List] = None) -> "Stimuli": + p = Presentations.from_stimulus_file(stimulus_file=stimulus_file, + limit_to_images=limit_to_images) + t = Templates.from_stimulus_file(stimulus_file=stimulus_file, + limit_to_images=limit_to_images) + return Stimuli(presentations=p, templates=t) + + def to_nwb(self, nwbfile: NWBFile) -> NWBFile: + nwbfile = self._templates.to_nwb( + nwbfile=nwbfile, stimulus_presentations=self._presentations) + nwbfile = self._presentations.to_nwb(nwbfile=nwbfile) + + return nwbfile diff --git a/allensdk/brain_observatory/behavior/stimulus_processing/__init__.py b/allensdk/brain_observatory/behavior/data_objects/stimuli/stimulus_processing.py similarity index 95% rename from allensdk/brain_observatory/behavior/stimulus_processing/__init__.py rename to allensdk/brain_observatory/behavior/data_objects/stimuli/stimulus_processing.py index b6e52f5c0..a95b04865 100644 --- a/allensdk/brain_observatory/behavior/stimulus_processing/__init__.py +++ b/allensdk/brain_observatory/behavior/data_objects/stimuli/stimulus_processing.py @@ -5,10 +5,10 @@ import numpy as np import pandas as pd -from allensdk.brain_observatory.behavior.stimulus_processing \ +from allensdk.brain_observatory.behavior.data_objects.stimuli\ .stimulus_templates import \ StimulusTemplate, StimulusTemplateFactory -from allensdk.brain_observatory.behavior.stimulus_processing.util import \ +from allensdk.brain_observatory.behavior.data_objects.stimuli.util import \ convert_filepath_caseinsensitive, get_image_set_name @@ -165,9 +165,9 @@ def get_gratings_metadata(stimuli: Dict, start_idx: int = 0) -> pd.DataFrame: return grating_df -def get_stimulus_templates(pkl: dict, - grating_images_dict: Optional[dict] = None - ) -> Optional[StimulusTemplate]: +def get_stimulus_templates( + pkl: dict, grating_images_dict: Optional[dict] = None, + limit_to_images: Optional[List] = None) -> Optional[StimulusTemplate]: """ Gets images presented during experiments from the behavior stimulus file (*.pkl) @@ -185,6 +185,8 @@ def get_stimulus_templates(pkl: dict, get_gratings_metadata(). Sub-nested dicts are expected to have 'warped' and 'unwarped' keys where values are numpy image arrays of aforementioned warped or unwarped grating stimuli. + limit_to_images: Optional[list] + Only return images given by these image names Returns ------- @@ -202,10 +204,19 @@ def get_stimulus_templates(pkl: dict, image_set_name = convert_filepath_caseinsensitive( image_set_name) + attrs = images['image_attributes'] + image_values = images['images'] + if limit_to_images is not None: + keep_idxs = [ + i for i in range(len(images)) if + attrs[i]['image_name'] in limit_to_images] + attrs = [attrs[i] for i in keep_idxs] + image_values = [image_values[i] for i in keep_idxs] + return StimulusTemplateFactory.from_unprocessed( image_set_name=image_set_name, - image_attributes=images['image_attributes'], - images=images['images'] + image_attributes=attrs, + images=image_values ) elif 'grating' in pkl_stimuli: if (grating_images_dict is None) or (not grating_images_dict): diff --git a/allensdk/brain_observatory/behavior/stimulus_processing/stimulus_templates.py b/allensdk/brain_observatory/behavior/data_objects/stimuli/stimulus_templates.py similarity index 99% rename from allensdk/brain_observatory/behavior/stimulus_processing/stimulus_templates.py rename to allensdk/brain_observatory/behavior/data_objects/stimuli/stimulus_templates.py index bad59e0b9..d5a7bfa69 100644 --- a/allensdk/brain_observatory/behavior/stimulus_processing/stimulus_templates.py +++ b/allensdk/brain_observatory/behavior/data_objects/stimuli/stimulus_templates.py @@ -3,7 +3,7 @@ import numpy as np import pandas as pd -from allensdk.brain_observatory.behavior.stimulus_processing.util import \ +from allensdk.brain_observatory.behavior.data_objects.stimuli.util import \ convert_filepath_caseinsensitive from allensdk.brain_observatory.stimulus_info import BrainObservatoryMonitor diff --git a/allensdk/brain_observatory/behavior/data_objects/stimuli/templates.py b/allensdk/brain_observatory/behavior/data_objects/stimuli/templates.py new file mode 100644 index 000000000..d2f92615c --- /dev/null +++ b/allensdk/brain_observatory/behavior/data_objects/stimuli/templates.py @@ -0,0 +1,145 @@ +import os +import numpy as np +from typing import Optional, List + +import imageio +from pynwb import NWBFile + +from allensdk.brain_observatory import nwb +from allensdk.brain_observatory.behavior.data_files import StimulusFile +from allensdk.brain_observatory.behavior.data_objects import DataObject +from allensdk.brain_observatory.behavior.data_objects.base \ + .readable_interfaces import \ + StimulusFileReadableInterface, NwbReadableInterface +from allensdk.brain_observatory.behavior.data_objects.base\ + .writable_interfaces import \ + NwbWritableInterface +from allensdk.brain_observatory.behavior.data_objects.stimuli.presentations \ + import \ + Presentations +from allensdk.brain_observatory.behavior.data_objects.stimuli\ + .stimulus_processing import \ + get_stimulus_templates +from allensdk.brain_observatory.behavior.data_objects.stimuli \ + .stimulus_templates import \ + StimulusTemplate, StimulusTemplateFactory +from allensdk.brain_observatory.behavior.write_nwb.extensions\ + .stimulus_template.ndx_stimulus_template import \ + StimulusTemplateExtension +from allensdk.internal.core.lims_utilities import safe_system_path + + +class Templates(DataObject, StimulusFileReadableInterface, + NwbReadableInterface, NwbWritableInterface): + def __init__(self, templates: Optional[StimulusTemplate] = None): + super().__init__(name='stimulus_templates', value=templates) + + @classmethod + def from_stimulus_file( + cls, stimulus_file: StimulusFile, + limit_to_images: Optional[List] = None) -> "Templates": + """Get stimulus templates (movies, scenes) for behavior session.""" + + # TODO: Eventually the `grating_images_dict` should be provided by the + # BehaviorLimsExtractor/BehaviorJsonExtractor classes. + # - NJM 2021/2/23 + + gratings_dir = "/allen/programs/braintv/production/visualbehavior" + gratings_dir = os.path.join(gratings_dir, + "prod5/project_VisualBehavior") + grating_images_dict = { + "gratings_0.0": { + "warped": np.asarray(imageio.imread( + safe_system_path(os.path.join(gratings_dir, + "warped_grating_0.png")))), + "unwarped": np.asarray(imageio.imread( + safe_system_path(os.path.join( + gratings_dir, "masked_unwarped_grating_0.png")))) + }, + "gratings_90.0": { + "warped": np.asarray(imageio.imread( + safe_system_path(os.path.join(gratings_dir, + "warped_grating_90.png")))), + "unwarped": np.asarray(imageio.imread( + safe_system_path(os.path.join( + gratings_dir, "masked_unwarped_grating_90.png")))) + }, + "gratings_180.0": { + "warped": np.asarray(imageio.imread( + safe_system_path(os.path.join(gratings_dir, + "warped_grating_180.png")))), + "unwarped": np.asarray(imageio.imread( + safe_system_path(os.path.join( + gratings_dir, "masked_unwarped_grating_180.png")))) + }, + "gratings_270.0": { + "warped": np.asarray(imageio.imread( + safe_system_path(os.path.join(gratings_dir, + "warped_grating_270.png")))), + "unwarped": np.asarray(imageio.imread( + safe_system_path(os.path.join( + gratings_dir, "masked_unwarped_grating_270.png")))) + } + } + + pkl = stimulus_file.data + t = get_stimulus_templates(pkl=pkl, + grating_images_dict=grating_images_dict, + limit_to_images=limit_to_images) + return Templates(templates=t) + + @classmethod + def from_nwb(cls, nwbfile: NWBFile) -> "Templates": + # If we have a session where only gratings were presented + # there will be no stimulus_template dict in the nwbfile + if len(nwbfile.stimulus_template) == 0: + return Templates(templates=None) + + image_set_name = list(nwbfile.stimulus_template.keys())[0] + image_data = list(nwbfile.stimulus_template.values())[0] + + image_attributes = [{'image_name': image_name} + for image_name in image_data.control_description] + t = StimulusTemplateFactory.from_processed( + image_set_name=image_set_name, image_attributes=image_attributes, + warped=image_data.data[:], unwarped=image_data.unwarped[:] + ) + return Templates(templates=t) + + def to_nwb(self, nwbfile: NWBFile, + stimulus_presentations: Presentations) -> NWBFile: + stimulus_templates = self.value + + unwarped_images = [] + warped_images = [] + image_names = [] + for image_name, image_data in stimulus_templates.items(): + image_names.append(image_name) + unwarped_images.append(image_data.unwarped) + warped_images.append(image_data.warped) + + image_index = np.zeros(len(image_names)) + image_index[:] = np.nan + + visual_stimulus_image_series = \ + StimulusTemplateExtension( + name=stimulus_templates.image_set_name, + data=warped_images, + unwarped=unwarped_images, + control=list(range(len(image_names))), + control_description=image_names, + unit='NA', + format='raw', + timestamps=image_index) + + nwbfile.add_stimulus_template(visual_stimulus_image_series) + + # Add index for this template to NWB in-memory object: + nwb_template = nwbfile.stimulus_template[ + stimulus_templates.image_set_name] + stimulus_index = stimulus_presentations.value[ + stimulus_presentations.value[ + 'image_set'] == nwb_template.name] + nwb.add_stimulus_index(nwbfile, stimulus_index, nwb_template) + + return nwbfile diff --git a/allensdk/brain_observatory/behavior/stimulus_processing/util.py b/allensdk/brain_observatory/behavior/data_objects/stimuli/util.py similarity index 100% rename from allensdk/brain_observatory/behavior/stimulus_processing/util.py rename to allensdk/brain_observatory/behavior/data_objects/stimuli/util.py diff --git a/allensdk/brain_observatory/behavior/data_objects/trials/trial.py b/allensdk/brain_observatory/behavior/data_objects/trials/trial.py index 1e3781cee..93f7b0f9f 100644 --- a/allensdk/brain_observatory/behavior/data_objects/trials/trial.py +++ b/allensdk/brain_observatory/behavior/data_objects/trials/trial.py @@ -47,7 +47,7 @@ def _match_to_sync_timestamps( # this block of code is trying to mimic # https://github.com/AllenInstitute/visual_behavior_analysis - # /blob/master/visual_behavior/translator/foraging2/__init__.py + # /blob/master/visual_behavior/translator/foraging2/stimulus_processing.py # #L377-L381 # https://github.com/AllenInstitute/visual_behavior_analysis # /blob/master/visual_behavior/translator/foraging2 diff --git a/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_base.py b/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_base.py index a967c84aa..ecdddb565 100644 --- a/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_base.py +++ b/allensdk/brain_observatory/behavior/session_apis/abcs/session_base/behavior_base.py @@ -7,8 +7,8 @@ from allensdk.brain_observatory.behavior.data_objects.metadata\ .behavior_metadata.behavior_metadata import \ BehaviorMetadata -from allensdk.brain_observatory.behavior.stimulus_processing import \ - StimulusTemplate +from allensdk.brain_observatory.behavior.data_objects.stimuli.\ + stimulus_processing import StimulusTemplate class BehaviorBase(abc.ABC): diff --git a/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py b/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py index 063a4fa4b..edb4b5068 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_transforms/behavior_data_transforms.py @@ -19,9 +19,10 @@ from allensdk.brain_observatory.behavior.session_apis.abcs.\ data_extractor_base.behavior_data_extractor_base import \ BehaviorDataExtractorBase -from allensdk.brain_observatory.behavior.stimulus_processing import ( - get_stimulus_metadata, get_stimulus_presentations, get_stimulus_templates, - StimulusTemplate, is_change_event) +from allensdk.brain_observatory.behavior.data_objects.stimuli.\ + stimulus_processing import ( + get_stimulus_metadata, get_stimulus_presentations, + get_stimulus_templates, StimulusTemplate, is_change_event) from allensdk.brain_observatory.behavior.trials_processing import ( get_extended_trials, get_trials_from_data_transform) from allensdk.core.exceptions import DataFrameIndexError diff --git a/allensdk/brain_observatory/nwb/__init__.py b/allensdk/brain_observatory/nwb/__init__.py index c63664365..ddac7e03d 100644 --- a/allensdk/brain_observatory/nwb/__init__.py +++ b/allensdk/brain_observatory/nwb/__init__.py @@ -17,7 +17,8 @@ from pynwb.ophys import ( DfOverF, ImageSegmentation, OpticalChannel, Fluorescence) -from allensdk.brain_observatory.behavior.stimulus_processing.stimulus_templates import StimulusTemplate # noqa: E501 +from allensdk.brain_observatory.behavior.data_objects.stimuli\ + .stimulus_templates import StimulusTemplate # noqa: E501 from allensdk.brain_observatory.behavior.write_nwb.extensions.stimulus_template.ndx_stimulus_template import StimulusTemplateExtension # noqa: E501 from allensdk.brain_observatory.nwb.nwb_utils import (get_column_name) from allensdk.brain_observatory import dict_to_indexed_array diff --git a/allensdk/test/brain_observatory/behavior/conftest.py b/allensdk/test/brain_observatory/behavior/conftest.py index 6f01452f3..2679931bd 100644 --- a/allensdk/test/brain_observatory/behavior/conftest.py +++ b/allensdk/test/brain_observatory/behavior/conftest.py @@ -72,8 +72,8 @@ from allensdk.brain_observatory.behavior.image_api import ImageApi from allensdk.brain_observatory.behavior.session_apis.data_transforms import \ BehaviorOphysDataTransforms -from allensdk.brain_observatory.behavior.stimulus_processing import \ - StimulusTemplateFactory +from allensdk.brain_observatory.behavior.data_objects.stimuli.\ + stimulus_processing import StimulusTemplateFactory from allensdk.test_utilities.custom_comparators import WhitespaceStrippedString diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_data/presentations.pkl b/allensdk/test/brain_observatory/behavior/data_objects/test_data/presentations.pkl new file mode 100644 index 0000000000000000000000000000000000000000..967e24a90a5bf0c75e874c95339005372453c078 GIT binary patch literal 42107 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 literal 0 HcmV?d00001 diff --git a/allensdk/test/brain_observatory/behavior/data_objects/test_data/templates.pkl b/allensdk/test/brain_observatory/behavior/data_objects/test_data/templates.pkl new file mode 100644 index 0000000000000000000000000000000000000000..d52342cf4afc2267c7ce3df305780bd30c74f10a GIT binary patch literal 20736642 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

#gMmu;f%Q`JM)Ri@J|M{Q){HM>QMBq=X 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

=-1oZ5n0P_}d3s`AdPydF}XHo3b(P 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

4ME}Qx?RE0R4&raoPEyb^ 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%0A9Y*K)kgYOW2$- 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�h8LamE488&2s)>`N=ZHm2uF`oP+ePFOMzLgKO;NuXJYE#0KXwJ zxb^S+8I#A29BS)lw_YHtr8W7@@mJ{0pxDEtL%)&Yzy$;j3fzLLz-qXYt?}1mCw$;^ zcEuWC5hM_H^5@ev*Olb^IefDiqHZ$TqHp3& zVZ&R~V9mFq0K(i657NBHUjnDa-*$g_;g$C~4;(vuK#$H}fs0+cc7y(+3`YsfPYD@= z)<$^{z?d-DWUGK*$!@g98bSvN3w*iaz{s!Uw|B3eJe@>qy0N523_zM67yMesvY6>0Kvm#)5F9Q(f(lo3E z#(=?JJ8~#TXZcu>Gzm0kI@BtmR|J;!3dVpbJ?a2jM}pyvK(9Aqz;_*~h7iNaGs}rY z!K?vb!%%!Ye)H*LB*I()&J_YU zIap{clT{Q)+3v8a5}UkzD+Qffw(P7tTywOEJ(N)LIG3I;T0Ns6V*trT!J?X)%cs8c z=r=YxqA4YbKb%P^aKNu;iT8=q$N2+?o3A10$6(h5=`die%M$e@o*ycHL3U5EA_Fje z0~_hL=gg7UhTA}MO}N}~`e8?hd-8kSC~FHjrucHO-<9R%Ws7Hy>iyX}Z_0jca>cw6 zdLh4Q=NQ`6ij|g3xGmbtFQLT!F@$9ej^NAS000Jsg9zuANaz1g=3p@j@T)lrHjr%E zi?6-+)eoblE-c%)Z71cwLS{NhZ)A?V*RASlI0lGbPEs#D(b;QTSm)Qu>pcn-6KQ! zB%yCws`Jmt6iPIq;G{siwnOH}#pAV1Ux-P`TS$p5Ho*U5F6%!Mt@32@bLD#tqGNbI z-Esj4Mps~v3&@VyZYdSRG;@=m-T7$ruz`Jhn0!U+N#HjJ+H@3Bbaq&{Ckq6Fz;CwR zC>TSSp&VC$o~Y+l#&8oNbD!q2FtTUFgT&tqfm`4gn2nL9x&YjU__m6+C_g)x?&+1l z-*|g2(%X8O47Da&{KZIn$aP#jg~DOPy~zI9@@MY=e_ws+g}=Q1VfUe9M-A@X^_y=x zp+0vt@s_3#{ZesIK`4`{s#3KjPLiOvEP(@l@sldvvbnRbt1%x_Qo3uz-d^26xZ{7E?f`*EC*i9@?*K>oERah3>hk^&pEKQ)+Hr%Cpd$uM9M4~o$sF9_To0Pa0* z$=1pm6HSjd;q&Y6YSylrT4m~^Ng8Q{GYie2ZK7DH+v|YZWf{hoegUj6u#UBep*(}& zkg{tz=CUNM-)VMv@M^ma~7b14F`-*Cp!ir8atmEJjJX4ztCEC?&A(1 zIkG&%Tw!;G(OcH<+`dES%PUuIm{3JD?7^KYXO1Cx5du9@*Fa~3D>vGJE$L8fUiY;8 z4FA1;wt-e2w3mvV+9T=q5;g@iIBF@+A(C_040fAiSCy?Q&z=*0wOH_PDq{R77{Oc3 z9HJK(o@5glC_LBq;i&OLvlb<29G&0HxQ_=1FW1Bd=@G?+`=##n2<8g zIYQf3gz$s`y7(=WG?A`lRGymF^EeCi!mg=01l5pcK;hCZTUff)OuMq>^PsldjLHN158&5S6!2m#ZA zqJ4ycg(y)fY@zeI%?K|u}ZX@Qz=B6 zHq9gp>VTsimf4O0#D;?@y_W?qm_I)Va7hT#)B!Gp8LLjyCb}%(SLg*t8RZ0nBN{B^ z5)5`AFbl}yEfRD_gF~NA4LQ`G1>of?Sj!~~=FKi1JFsgZm3%G|~eKOO>1M0FP}Yq#&*Q(e~x`6Wdf@(cJP ziV`nlMrz<|3#q~Rt&A>9C1>l*_gP9VQh!Szu1 zo3H4fVCk+ycLm^ESXOjyii8uzxk*v6eh8^4ZUT#~ zmvev|7n1Po++iv?Eq^r(fgARp@L#48Rlrxlq;qF@lLSY!;NWANI1UcGyEG-M2lwsV zx@k4lF*B!58ecSWqG_W#Ymn~1Fkqj8$6G!`wcUPNY_Q>-Z1DW0O> zD*B#+^CR{PyG)qKJ{N$Y#Kwc!cq&T}AvFO%nW69!YgL=zjD+@@c|k~?#V_-XM7BsJ zk6l8M6C(2&J>k%y41UF6AlTC1==@BM+j_hk_Vye@WA*R4d_(dxQMJD&&`rT!0XHf- zEcXzOxyYz*WJSY&9XSAJc28^qSDyk`&^M>NPW_g_y*!%XI$$Npf0?@3U{1#f_{~-5 zbc6dn$niIOLZZLAoUP$Ey+g}K&;^K*P?k>~kgK-b2743E<`&*(#1n#WfxpC%{_^}w zZ-3Qq)VMJ}|Jbujr%s)N0HZ$^xZLuK3MujsKS_p;*JAhyU!f{6m1=)_n$Q!5&?mEO^ zqrrxGJ@g*%SpbIbDnxG(gi~zT@b5ZGhsgv%fi6?eq7~NcX+;COeHH-x762UnQ1)x4 z8!c)Ef`tIw@%xbrHtuE1Q8HUFIUzTt#g;N2#gK>s%YwNf+qec`vfi#mH(BDfth#88 zbv`NvU8Fu(*P7l`sDjavgNH>?hpitb==FO!)c+`M#_u9T8i413er%Qv3NfCk3%o=GjH z@3#lnn(D#dE8ru+EcQ);-)gbWoDzR)YYtUcAEaF`reo)>z120xPG5w*@*OEo=4(Wf zl)Lj1kEXws;Yrh>aSj0B+hlBK0Xj_NEj2;xn)qvbPX#;(3Z1$6Un;Gj$318Z+CLQo zn_`2);JS@FfF3uzjcjjJYqY@|bSPmfCbrG1uc75ea$W$U+JaUQV zjO+9D-#Qdrwy->sUsFCsOXV{$6Z};eYxm;w)*dC~6?+r>M($PN;(z~lR&n%aJ7oo0 z{~vNz761E01PG= zyr0IS<)z^76!%cgJoyy88a*23J7V}xn4Q!IYdRq*d~mjnCf-X97FJ-sZQ>b=O6Jd+ zJ{bXEYzG+5MA~g zMZchLz(I&R?xqraToQA7Jtdz5v44#Eq@l5Umg zu00MM>6ZBGzkuJwfZuq-h8z(TO&BJ+2Gr)Dmt6<%_iuo#@ zioR0YgtV>%M*)7tUr^XbWa!JBPsq!flKj3Hqs<4&ynq6h#z#pXr~tp>F@tZyqrsxR}J)VnI3#{({E=z*1oT=Qy;(^-|=Ng5@ia*FiM{67<-CU0}fPz<{%MMd=4( zYAH@656_9{TmyjL{iN&g`5X2fA=yRzHS^JNR<%h#*M;Via@C2d;3_tcfkbVCjaY9N zFT_ZM*Lr=|cq~QqS5?76d=qBJ%ejL2UmX?vFl|U2PQz5J=19{@F-*WWq_g|9^0D|4XaSSJ5ARJU7V$n_SjKzj z*9VWn;vx$oOQ2()!>SUfHc?CiS5d(R@VhDU5P$9R2mCHuFm*_`Pu^z7?yyjqQ6Se! zho9zD{x44AxWD+)tLiG?Z^nNEZZrKkhhDRwGjn9BGtiBpG6Op9H2>i9!|Jld^JY(- z0RG~~XT=pnu^6$@+u)(YA+_Tt7tfqcMy6YIFJ+jLNmdAQ^x{Q}Y+uRd!4oHp8#`{o zRHDC|_a1J%`2X?t9t=`dX}k7Mde1kbWEDkpOei8q&L9#b=bTY;&N)dAlA74iG&x7f zlGFGf&UHO&@9JvAQOEauOR3xiUA6bR)_p%=-MY`_5r5|2`X64y&l9D2{Mb!9lJb?m zo?hXuaON`HU4gV@eSF(#6QT7NG}Vn$#19>xm=QT}#NbuPK$VZ(1)%3Jhq;HU=2dpO z`zVL0D{r&8kj%!?Hg@+ETaan2lNP={Ws15M@8zWpj-1aRozt((`cS;58&lgE!3 z(6e*<*0|4Xd<12cxPa9P%Fw(Cy@B8y!nq7q3PWG{oA4XZN;6FeAWn5%eg z&R!znak5Xk$eZgX`9G09HTaR9bjE(=sU@;*TBPxss9S$`9 zv!@(`5`=K1Rl@VFN`k;#m0&*zR&C{inZRmb?Sc7u>HX4Yj>5RfSK8FnUcEW zyfpkPMgs_O%9%2G*@AuZUU08ex)8z*53C;MzLa1))(GUrir6?&ML9yG>3Z%4gyY>~ z`JAygrU-?dlZCx@Fm5%^$VDMw8h;=!?0vzgGyzqbvVQ$HyU#s;rtU3r@o1%So$Y^^ z!%rN?RHL^Ly*7%Tuk?O}JHI}^d;aj@6X&nc`syaV35g5R_{h&A0Hj-XZ;p=x^pa6ZH-6+1xA3 ze&dq)h-@q7DDa!)LPlR7$_pCk(!``HCzfP*76dUjHb#gW2t<`)I9nE)Ig{|&}oU_f)cU&F{D8;QRJe4IY* zvNSnEcEl=U58y5I!LmMe+^FG0@Ye>LV`9!I%C|oon)mG4(+>9(6$O6n?o7Is>UVaU z1fnj2wmDNLv1!AYu@ionHh=m0om8$}|K+zC_=RKfFWiv77M*hpy2#}K^DuFJ$2lz~ zIl``8Bh8zH53!2KH{D87X7u&bXV80$^$&|47v;_km)NC+1vzg-V;xt1yt8lX@US&M zk);s{Y>`0iUJJZ)nA*Hmd70s#a<0HH-LE)x82iC6x#f2L+D;|ks$~mjPy1o?kUsgw z3v|A+^|J#2XZ+19XaOvcLk4FGIOlI2TOS003o1B7Ey}S7VL9bUiOEMowHh;>4M9x( zAdgtpuY<#zkrTJlb&|f>vNhNn2Ycc#Z3zr#pD_w;} zRikQ+x{W#y8q>GucU`~j&{o0*YN2gDg1X!Zn9>^>1~b}LNMv2+Y=GuKH9zCaTZ&$K zPCA+~0>MpFb48n9^`!GvY=9K?M+F6(fXm4eH?pfC+RizAy*3RD`kK%vf=AIJWDEv0 z5*QQ*e*?h5TG8hbjBOjV3uPG!9i{}C0g$vEZfWVFbv07LO>=lD{ zbvCQhW&Tm)Sq95qE0SW^2q0AsueCKL1Xch~n=*0CfX>b9lP?&JIHH&{oQhYz(%>%^ zbls1?Y~6SAitPs}x3mb!t<5P{fij^kocOa5XKie|8kSY~QP*7Tg5xj(^`>nhAqxTu zocIy(MB&8)#5VO&Z;*SH)GvtUHQ?6sI1S~n+KmM}r8mJ}&00J~ni>)34ITVjpSbee z#Qa%P4Bth_30nKD(a;Ogq<($9lVpz3Wjdwq3+GXgZc`MelLDjC3y?g0UcDO92 z>2m6SjQc`>lP8ZIKXdBzc~(xk|I`4Zf3M$yzpmC;!{FfaVY8~iS$O)CG=bM00@I{Ak=}Y%~S%&>@2c_K&`} z>{q6n@hr`?EaEx}xd?+$e-P1MJ3k*J1RUKbV>9ZV zMn|@7O7eFSohN&A>Cn3Q*I$|Z92*}c{#KOxewbU)$$X9&aK>nbvI00lz_cI=Bboy| zR+yknC0R5fdY6&#E3(tGZ%beiocIeq1HXyC#rUlZ;*7qT_v|5_ei8;J0w??y(N`f} zK&q@Q+=+j34&U_e@!u4~7v;CJYu{5J-6e9(e>LqkWOUC?ZQXStu@`m*W4Q>9#{CSx z2-=EgeO0^n04#*j!0?weFH^h_zyAPW+~PwceK!P*xgbsJ$3XLXyW*jNmn@_e<+RB^j2Yam z<(B}MBhWhF>|4qgQ2Al!Ay!)e|LgOXy}w_w_2ALtr;PJ3;WOV5Wiy(q!Zn5)8aTAB z+rz|6WTqBpq$VH%NzQP|dpmNi!fquPbUT|7HNjkf$0Q)7xfv?gmAS9O!YTlm2O^`$ zTwd*2>{>)G1lCTIF0{S->(!mkQ_mjUxOj#H6Sk5)b^hFitG6Hi@f7{*i@TSOmX@<) z(w$o*#v+Fh1Lv5EoQm=3%8mdEGdcI|E!n&8KxsJ|=C&Rp4k$U-4<5q=GL;!&ER(ma zQhQ8_m|ZFFvp`{srqI6x!qbNs^P}#9?sFuNf*N!M)8^&N*RL@Ha>v)+B(99S205UI z*fQepfghPze|X2W&ee-prnJ2}cz_%+NgLOJ|ETr0eH5i4?aaiM%-i8>YtRC?$du>I-i}NiQcl; zwlm8RjOaoA`%)Zfb>w$F`wbp3I?8`(e?{KaqD2er2$1;8R4`{Q89QV}R##dnh8dFxjQ(Zy9(mNvAmpk?%r~xZo>9}({2ne1@|Jqe zz+bmM;v1*;m176;m*i(RUKl>G_jjGrzJuhG%F}#^SVm}FnCtLfk@h7>tWb6c;5uHs z8-t@aqp!RzjPzVwqL=}&e_W3yz)4`whv08!=!E?Bn2r%JF1i!Xa`Z>^SMOP)C-FCn z{ua|W(yydxr6E$Y2V%}n|CS2i`dr1mxRu@%0KZ+MYSp(sZQW^mj%2A|ZV`YX zZuF(}njw+pZZ^DIdGMN+p?le4kGQX@Hvw1*2Y{Q?W=jLQt2M@My%0kJ3)hO_0~vEG z*c(rKmjQpRB8Z_3WJSdtg>}~#sKLmd-A1^HB*WSrfBc+&xkuQTc=%)9 zN^6^TB#{G+?7nRl>Uoluj#HzI`)urY`{wl|_pOZs$0eP42Fn*r9oD7kr}TY}!^AV# zxrQaWi~X2vxb#NV>e$a7OtorQ{#(J{lzvsj-vDy(H_YakgmV7Eo#xOzLgF5O7`yGPXbmMvo*WqkbHdN_-VRrpJqbGb2xM6JO>~eIQtklV3LbM zT{L#Qoxk|ZP1j=$R1y6D!!J6$;3e&~NhLSeju<=@G(b4XZF;V#y3d|0KfHhU)*n}< z{AYr~!AO&U|FAU_Xy^8wRR>XIk;UFz_2WnC^!Jh-b5X!}RG>Crz3% zea_-l8@BI1!LHP=^kn;!|L96D<9DX-2IeydgGJ)**Tq2vf3KUnXGlZs%WrilKa

5(Ir9>L%Pj@WsyWG}139SOfAKd)Ls>#I?N`*x@EWYb18p47=J9>`jI zJ*Odf)8M{0;wqktpMkw0gO$KZ*@D>uc$K_9o(4ME@t%S?Vt1iKnLE+I;Tfk>B010? zHv!i*D93c%E!^g=`1QQe?eSDf0boPG$mz=Xt!zI#Stqu7RWvG|@ZaPUURNHxG0)Vh z_GXpZ4Za=v{lxy=zrlPaxcjR6ERGX&jpe>d-+(nFHaZ+b6es!HA{#=tdGolV3Ei|Q z0vG_djUASHQh!97>1bNX1;8yHgLq`f5Ld3kHk5JD*9V3Tqma)6;53F?;1~Awea(+sN5J?mleCzm$b#KBW5AD^55pPfj;ixp-I3Noh8+D8Uk$Tc{AU zt}(~pu)5ZAS6L%|iGDJpWjisj0+&RQJ_LYawRBg{X^jbH6r$q+U{T7DLq%=o6KW|C zjgSBPwgkUEe{k!HGYE6YIr{tE`sHDz65vYnSbm2MkdBoeK1o@~ts7Tx)xfR*hHOkL zRx&b4k*n)YE{6`WZ63WUf98!d_wzY4xF;W+(5WF}(ZNy#qZo~fc1`^C(}}<@ZSlS7 ztaj-tH5?Eimnu$|W?nIQT7s;}PuC7&>%Snj$#k^~ibS_Gi}$^U;vp{hMPGa+a(3-|eROOGP>%gkV|Nww-SHYN|}4@Z@1WM3uzk`--B z$!z56SLvJlXU%6uSj`~;_-Qh*3O|wn9B-et9{hID#Q7`NV~e~0E%@Dk(5b(yOy?8( zndu*ElpN%8ARbr=fF9Avi#tlomJ1I}Z&!k1f0B&Yd-5_Kd7$!1UQD|D6YpU0_eHKlWqt!}9m8UlRF#7Tw`E z2oip^on7M48DtD;wjJFa^j zH`1m2ty%SrYIVMB)3sN>fjz%%2Y=fYM%xMy%T(a%Rouu>TXDr}W28rTQ4qL=f!`L2 z;51tBKyF5pXHEa-E~x=WY(5BU#VsS<$}fvGvCn1z2EEqPv!DgMRsqZ3xDg6CMSF?#OTxGPEhS7Q} zyyZJ4`$|y(tjnyT2*8FV7U@F*8wXLX90Hgt=o^}u9|I>(>=uQStC?$3^8Zz9k0W?@2s0bFj+gFnv8> z@v+nAFGuUZG?l(&HrH}i>C?}Om5NQ9Z{K@}Kzs1e{#2AD*>Y2VFeLD;Tl7FAHAdqB znc-*5az_b_9eQ04;TjX4FNWpJvA;Zc@|+eVm;-!nE?FM2;S+U7ER>YLB%IPTV$Uvi zkSFVE6P<-D7{_$MZLufnf>}TGYxmWMY*zLTzB0qP!D+%~^O3lWgB;cwNUm86` z4drhj){Dg73hUYXu-BQ$sVLI`Ojv~<;c>AX$z9mbpSA2hY|_Ft>o;wt`DDqyeaIp@ zaPYa>nT-xu#DJN{5mO4PC`Xk75sBpE055!G965wKS@N+UfxizZvA)lz@|uF~!qM=1 zH>e-Sv;e^YE|x(M7%}Hxewtji!~1t_*|2))0@`1Vi~1wXvXM*(qpADFg0^z9|A4{6 zkiQcq6NBPR$9Pr)Ltn;x>W=2lVO`F)M~vw+=PX#hVduf)=db;laLDidn~NTQX}fcr zBR`3>(SnJQ>Uo>Wrp(DJoV|v(BU0jx#Z30E76Na5ZKpc)*)G2 z>faRp6}}7*8~7Ew8F=FshkT+h2R_&(@cI|iTe%@+u?=J1zv~Ek?Z;bZs&7&%)+6=Wt_)RGGH4@wF z!bqeR!4Q}2)cfulXNwrBD#2rjdULa0jXM zs){}v&XtDNFW5=zG7~ih$Cg;g4q)Xf79f%x=H+c_Odds!E`~oa~1xlb+i18 zRlN4I$55>r1ceJ)HpPEoZXxs=>i3^-$X+A?Tzitgsb|0idH5P|T(n}nC)Un~KM9)t1 z9sxHuS|a)I!yjDHH;t` z%ZS&YA;U+K)jV@4pOQ&eGLqFB_`RxEd@1+V&6WyY8dC}UmhthIvr&RN82qvVQqIC( zRwK*c=CGsd%nE7+S2dvEMk{l>n782i({A3db6 zjVBv__2uWd&rD#>Vv5w_QG`s%3qFg1TSQZCDndg17QaEdU5sAeC*COou>6e?rcet1 zhWri0azqzd(CN5lX(@d(*C+Fw|092$l3y9=@2t4Yo=y+sto1<&o?m;rFqq_PRsF|5 zs(;*?PqJfMHXclEH()RoL@|B?VOg9Mt_fS&s|r_8xBzPjoa5KqA%P(7QwThEV8^d$8Mxdwyi+!fRbjK(OqdE+YdgfL8$kQl9}Rmi99%185otT#Y? z`wsXe=BWfG>E;>zGgLhh6i zU7FVWfL^6>E{FOJpH0!5j5e3?v4p4h6{odpYYey~X2os*SQVU7ul`S_i(?{+RA-Fq z>h`PThtfU_$OPssrzrXR)`tz-_a8rN$?EkRx3K-*P6146&Y?pG`9zufkx%4a5d}tl zo}(26hvaG2K^%ow_#_Z@AkxD}ABA<_eNyfNz)xO)Um9WM-@||WmMcBU0cU)koa!j8 ziBIy(>8LgWs1 z<}YM*JPRMp)j0pt7@A#=e%g2Rtl5BnJM}rbXtEwN1CJFRYY~>VW>C7mi}f-_G0jm8 zW$3JMSaCJ7`vq*()_@1a{O zz?oAshj3gM04z~M{`y1wk=yV!AIYkYx8TA6a{Qz}@oowfzw>rdzv@?)rXKzkBU8V6 zKAHaIsE*;v6X7d;9sW4uH~KdrRE&l^O8SU@7}3h+ja@R9UU;(@rn}8#4KtS8QUC;LR%o*-r=i@x6o^4AW~WI(4)lOhb9s4Gt;aPYQ*zlFO=0E5}#NfPtKkRge`SqvBgXK~;J zV2Jz52q6rK6~Xl5h)t5hYl;iHbA%waKGYs8aO5N#VX3wXZf3P*j`v4e%842 z=*64&FzuDcw1?@W491K0yt1M|6h~@>{vVNHTxue~(WwL7iv7tM&p8iol(F#gsruLY z-#aKhrvmj`@E1SU6e0vhKqx{~Tf+TK z2;hQFfAI(b?5~TcmB01_(=njce*}G@E-bfP%QL9?c25%vcoqv*r@N7Ik%uu&pgY!z~8q&Y1(ui@+7|*N1&y0QFqQ7FaXSY&VcxR`ikN2V+*{nW!hgnM0hzr!(!$kkpua~{uSo2 z9m7c2x0}r?HmtSz6~W(8!v^)!V;e-@=a>w}LSSX^NMpaKUp{6|^4T+~Kys<=x$d?s zeEc&&Fu9qt=FDHXZ0(j^2acV&eCuIh$@bU(#raRLSY?q4e_4ikaHJJP!ms%oYG4m6 z{*P3t2<2kyF!)T*@<*Xn9 z!5Jk2HGG{=_#g(yzJ2hwgqpqGyLRo~ZRIab$v2wT7WnP{ZM&9D8YcCdaW@1kjg4c7 zQV9&0lMGJKgq(s@z6L}qE_`K%@p#G~&7Mu@jW}`&CMO}SWbv=l8p0Uzw8#p8Bmb%Z z;6&X5em$-k9{XB9VL=!3*SFz3tDt28zcDd;A!IZB#)4N6$HRpm%AODHn_gOYiW|H+ zFRxX-TCIOI=}HsN&K=spUm9pIzG3A3G}u2O#BeBEI!VIOX3eN0qMcRa#%ft*aC_*> zPj&2|7o90!WwPLPv|xzeW@!N6JOG@wIdl_4N7B4QQrdF_dxfq%E|Au{0bqeUG=G>E z@F442gl~c`30RII>02Q1cone28-O_FLQjpofv4J=(m?})a98r`LN8pf zFy%xeifvMf`%KG86RwE*;xxnB#N80Vkk}3!0bnIC0$3w^!Q2^BCywsdvB?)7e@I3` z9BFKBlesB=$;jTKQ5yh%@JYi?Bj&B&bs$a`w?8M<*K(a$^F~!t*wIR2Z>WuRrh+;`{6=&$ijeVx$4n%|dS6JEr)1MG zrT&f3Z$3diyN~L=aort^F};zYzx+|RzXw-O9N2#dfkHYgt^e6U{KPS*6*NLAVag*% z4jyDte+@iLp{yBl>MNy77%~qjq0`Qwft`A#JS7XtlPM8 z^Y)*1?B26`&))qclOusc1INk+4tPY8iF=BIQfk0FDnURjP%cM@5@W!utKct7K{O!C zx2M<;@b|w!aI`sjN=r%Od}DDFC>B?b-!u)a`;+1K$mQ8?C|^0$CreWV<}o?0;~;a8T%a8_n`JKf6e zir*Lo#%3Bg$8W5ieMQ9!(7z;U)cUwZj}e3WbnV!_eFwNJemmLP%07~gc&G!~Hh^j; z$*&u+lTm{&zx=YnSMFw%jA#kmv19VBGXw{KTR3v<3%MOB1GDl};a-u{0=9yQVbK{Ksa*=7_@eUsdGg=`GfTJ2IffofF z{0$d+Mp)4E84IY-FAP+$(O}hZQo!Uu<3Gb*@e6;sA5E{kF5p)LGswX*gL>K0Me}A( z`C;6kZ<~HWAuxwjcrccD`VGeyo715@T>aC&LzqscLX&S{9-~v8bp{T}Y`UrHc=kICMlJv*w4tTEl!21z}C&E&e(tKX;a8cLwmwua55w zU7;-rK76+40f~D((qiKpDdn`<2$N8spPN)dyqsO-H|Wjh50RJL8ky zdHVeEvnLNFJq0IZYV(%16Fhb7@PUI&b$e(zxp^IX9f98&(`U{k`DYr%FJt<)Yxr^9 zcQf^yv~Nr@@)yI{nFNB?FeTbmwNilSZ9!`G;{MhxYG9d))7O^rqIAwmcDbaw-_>zJqT38}9QgF>AjK%`OtL;4WCRz2 zV`5+v#TSb8d_Vw;Uwg(8a3J){hL~H}4|C131v72DLF#kMgx?QS7hSai0M@e$7N?7M z!%yZyvVzkBesi>D!bA73Vx%XzbW()0(X^85tgW=y3BUYEq$N6I<_egVq}EUz#2(0u zMBa3};u7&IdR=r1V16!#?^3| zZTpU-i*~2>@HbR%f^QHwQ5Y^)KUz+=XGngw*njvftrvpX4g3jhxOh6z2H&R9l+vw`-QKFy8E5Ww>nGGOka ztP*%hXkqm*ir8f6<;w{IgWQyHWv*2stki zW#00&>(`NiTOTXipP1{T(r|SJw`$FrVucn%IX`ml8->0%miU6PDI=oxpG6D^!i~3W>AFd`NPMQxLh?1MySb_WG5F0^c>OzFGC%2Hy-EIcz|WZ#%SWAJRA4I(N?T%Z((1 zJG5=pq8YYxBc$&apV#~JlTSYRtlk%2HvGCtbLx4qpxd zQ3gDk5tYF3HUXGZ&w3>8r;!O@H)Vjo#Q-+@!b~jMa@Y=f;X=B@Dufp-SQz=wmLQo; zMJ|>A4yY#IS=@r!)eht@SY8v!S5h|soMCtw4FaZ388@&?E3&XWv^=C-&t<#~0B09* zP_wjr@BM$(Z{2hB>^0l>9R??<>6(5me>>3 zAIt#g-$(+1yb54-pL2j0DnPl**^4H00*xdQY+)Q#xB7KpJV)&>?R*{^OfKXUzYdds z;W0ezr;lPoHvf72n=4TH+jsf(>CJPcB_#*SPE(S5;q>vcqXdAs$SGf(1?KlxBh-B^sWxFUyb~vD|s^@IGxq{8_?zXYD*`o1xe>e#f>= zKT>-{A*#9yDK=~Bxc(g*e_HoFJY^8c@c0%$;tD&9!SqE=#Mm6v1WaX>{rK{Ac+n{alF;nL)TZ6%~Y0IXq zJ9a`~6!3l>Xj*$x3LHIyaWTtj$ib&vUXHke!e=-p`7}6usLQ%R8hPX%+>NH&4>?}Y zzfWKM`qHoAuSJ377X#lHke4K@IpIAU|3&s{LzDP6o0jnAUoBj=ioVx7N)DgC za_4d3i23bt_-7vRpY6hzV1zYPoQw7cCmvBqeZ+S$1RV6`$nzM>2por73gO0%Px6)= z!?X%F4J7c(1xI0wEPi~+76DEUhNBSAVLu~)kCP4|e+m4eeknS#SJ)4I9( zw=4V|py-9E{Bg)u$tqzXtMCQCX>co^i^sBycv-wOe!@y%`3rPOu@J=a7XpJ^`OB)8 zF&Z^o!C!1>C9qjo;+LWO>`;J^fT0ix4GeoDLxWRu!9v5nX$auhoPh^ctc0vUcEt*= zgT3}L0>{YVl{}dZo(p$+Ii;P`r%oI*uyczqKl|hp2pq?hG2r+<^HroWnBjNkin8vf zjXMpTymU*+!6O7SSqdwFwVkK|_Ebf#nk|%qNG_aX;0TLT=mwN0A01lT^TB3F^RUgrlq_(dxwu0>5^CM*6y~9Jw@qKS4Cj#3+U6 zkNe=kT>`UrAHHtm-)zF80oM6r2lnhOJ#~?OQV2@s6lN0yaQV?gP9-$HI)p|$Oz*4X z=!Fw!&RxXtLzX_Ea5)>#A5v#z!3XN~l2&Q-biS@_di~Z-e*4R|9YX*!F`5ibu-HCh zG0%Y)@>Jn-jL;j@E~E3PPrXI3mljx<{;pacy7aks`v%jh-xvLSkHRn22646>r0uR+ z&c5#pJjNExpF3^*z>ZDoeE@!Q{wC*H{5mMl1;HjzRR^M+?wr&y5sBwY{7s2h;XxO9 z&nfjPk=rA#7Jm(S(7M-Zgg3~A=3T1P`tYl^y+==-yA+RyM2AgVwr<(Ei+a$#bSK_2|t#^0?#;(X!v ze#CF?KcAz4!@-IKPd?8*R%|#>dQ~>!h?O)abgTa5>=v@Ed_&S5=%a`}UG@WzyA88GYGK#$6XC zC;YZ)-nc=%EcBaCPBCjaOC@hMH=r&3Z>z>lrKnggvNZF zUBqu#^g!H?GcSA4ABvmVPjlPXa8-CFcwD{8n>9ab-edUakyIdc>VW?Yd>L$NR57?O zfjhQmm*uaqo~3UL{O9@&8a0j$6_CEEXxRKK6R%Ld3BEyHRBywEUo~vxRYNW7)^wo6 ze>VCnb&Cd!6{u;1%H_%Q8lGYly_TEVtJ727i3(t$D}j>;7P=`O95*-z(}2m0vCtR* z69Xm+92B-OC4&>sL37Gf9%xg#7_5}dhfc_@moqb#IO8~T305>P`)~0#DP8U z>4E{tV>wRhGm{-Unbcv3%N91zpL5}a;-dbMi~2v9Hviny1u68LNboQB=+k)f7gDQ# z?}vYVaqq(M1G~wPp$Ex@lShx1^Iw`(uy(;)3H_Rk1DBT3K8Pe;BEW8nhyHz3kuUc6 z?yaBAp5lKS*wdTJ9iv=!5Dr$62wQ#*OPR_L{paZOd65r2areAdKm5LMf$gR)T_Jp~ zrD!b^=~rPiK6t9YjK3sc$zX>5Tc}?)4E6_^9%6<_ zKbod5CM{;Ie^!0_!$$4;jGi)osm)exu)2vX=v})@{8;zx-5WZXURb3xHvz!%7i$yq z;TX|LEShsRqQs(?zqfD4{~T?Rdw>Z8i*N| zZA?xa*}rS+hSlJACOwOjxr?92hYYQs+ls4&0(?C&iwwVypz9P-x_(7iugM{v#=04D7qvi{u5gS8&9 z3f&S;Xq_#Ve4%oUIT`Lff8LWH{D##Z53&enG3YVrYBJ^p!5o7ZM&%JpQ@D@bx5A6{mp$jsb-;6>qamU@cV|A9yC(wgRUK1~WnkvsjMv&pzv?D0G2J$A}eCwR-Iats%mD zW=4#9q_hJ)`z+uSB6AIZ8v49+kxQ#0Qa|I2zZChtpm!1AeQrBm3XxdSM=yo{G-v+l z=Q36L>r2AG#0qcyOu3M$F9o$)`JGRRRJNpvZy?Eg?nLxxM*+mTsv+-}N=J)SC z5XCa(_K0BKx_J3#Z2%_!f@6*Vrj4^kUBuAwOp$F@4G1&Gn}-%~RsdhMy%lNFY+V#0 z_U!o-Ut?m7X_CzkUH&Lx*iOj=XcjsA9=}jGefOSg9P+dw^|{lh&YZBz5WVepQ#P}W z&3@OgEMp~Smi+vwBf2%K_kQg-qifc5c^=j?Ge$OT2w`~4e?IAKQ8O*EYi0ePGyY;i z|Br1a-Fq;~k%GU71m>QkoSimel3*4~_8kH^Y&$sp7W%i>$jNgTEo0?qr}IslH@OYr z?%kG$?%j)4LIX$7U{*cO>@e8*-5eh~fx=&+=~xDV7(M`S^UEV*AJ_p;o+1LZQ#hU| zkbaS6^i}?X3-^Bg75qJ?)ciToiQ7L%HL%*mpNF?T!iPux%e|pt_gC4u@!!_!4UPYNgu{@ zIik5#4QC_h%WH(NdfB5o#BwadkMr%|IHP*Kf$SxOAKk84qsn0RTiC;bF!6UQ!=_gp znM)VWnvAQT+FoHkf1vf8;aBE5WDhJ%08%bw*;uKaRo>L9vJd?}LN*(j{LM41P{0{{ zKS}TfJ@6MQhg4AjrvPx`FDHoU&qh#UfZ3q$>+!4o%n161{hZU6GbuUQ75ojP7VsM< zOYzJczk2b7PkKKGZhFppNg2C3q58L);os2%=}F%0+m0RSiP5D3z@6c5HoA4|+T~l0 z@~epcMj3Ecb(Ct3TC_;=H{)*+h8s6d4WN_!1;0tzicUr)_Gb8f z4RPbO@q;;^E8azZ^JnsT^SXI#OPoMoGj=}A%kgKQ4*?}GWmy*z1x5N zIRSP0sOqXDLnXee^d);37k%Be-?I>@{eWq!2m*T+nTf&K$nYc!Un zPadaP;{N@lnX<3Urj6^Lb^KgpXje>r*if0bGvG-%Uf z_{3TBmad>F_3Cv1csn^*yLRr}%|D#fG5JfD+rj;ZECx=!#>6k(5>K0fWgW2Td$(?B z+~c)kx!lH#M*+HW^B{6OdHVS2OZste82#Qt>$z(_kBR&D*lY5)xBBKq`4T z{fqbR!WG6T9F?X5@vB0Hz04DO5@OeIffz>k zB7P4ag1g|CLO2HeEn&N(+f0lek5Jt1UjT|c+L^+H0cNm2Y(eRq)ziA@Ygkf$8F#@i~hbs zU=wcD7rQWeaX?@t@QNU>S{E%NidQ?BTBUK~vdLSFB@5XM2?M%+r)CZ68QMSr zb5KjL4lH+QS%+R4_Qw z1)=i4bmPTiG?D=_%wk$t{7x0p^ShT$9obv5zZ|V~{>%xpIggedqVm^90_d~7Fk=7y zgV8sP9h4mw^CGIPV}6wW*}uMgaDx=)GrR+JM4EUCD?UQJg6sB~3`bfc5H$PA&~587 zZ^WB1yG5z1Yn^bfBfJZUX*=epmRSq*w7kz^BC@LaPWVPnQ~X=He=n`CsIS~)@(|7l zMQdx(-7L0GLKyV+dc^$p4{wGu<0mSz6OF*#6ISfDQ=^fd3EZ&FHHO zo#Pk!CV;2f;V|0VxR7ZfMbO}{vLX0e_siDZhfbI|cQOCCRaDv`fH!X=GDsotPW~`s z8#5$pmXDZ>w^CIwO&yM%q}S&u7d!x%rV`f()S5v+`w@1gAP-RAgs+uj$ju02P|x<9 zjI7rmKF=RNB6$s3v4**E`7E(>7FlKPKz!USkG5@KU%c5fr%jqLZp^TOeZKp)eVdj| z8k6zav{n0WyZ5092kzMLkt6k?CrmQMgAI;2uj9nV;+nf~0dXbH=%6nyHf!;T6DLiX z2AvnL*|O*GnQM0+{ocRr_5b2mA0@=CekXO}*%N{`Zq-Q;J5>eJ3YzeE(!haWO&6V) zpfC%-E2IX-N|2Pm%N%EEaUCl_46fjBtiXf6p7P89TyjlIba%)w{=`&~j4;w8(7v!2 z0Q03;CBWH2Jb_VCLOdi-y(007&D&NiTQo=Wxlgx_;P)B z0GzuxMG}~2AaA_IOktXtwGI? znspyGu6O5lZQ9V0DhBp*mt6UF`>uPBo@w;>u1hC#pjl30B{w9NO9KwYEPE`paQz&N*_HJ~x0F{Cu1zn8%l19RFD3MLUNqCZvvTBVRF zU>R(*h*Onwl{6Xn8^uYB&BThaY=t@o^rCTt#}GIv8&SL}o=mSKS%hWw*a6faeQsbQ z0G!rzX;tMHmhsmszBaz)ckrO!|FB+@&O@dwOWm-LwK&Y|JAV$aCfJ%0Ee#4PIJ;@j z2S`lB7{400png##FgT@OvGn%jkMrC-E^Sos8_L)mksB1w0$W7yW5QR67YN2o3W%c^ z>D3A65AOeAsE^HF!=fX7*cMW+2mH%lE}tsfX96_8@wrpHEHXa_4f)W9JaS6dU2))1ZnAt!GvNk8n{1)<#v4^?)cK-ix54A4 z&0WO7yow0$h7B8NL`hxB4pcDhp!sn3lSFp#5PeP#;Y1VVFu&)-DJs-Yoj6TIE@roqm*h6G-|rXu*oBM^lqbY*yf$oYYiy}NerC9+Uf zhJ9MHW6PQqOXi!=NZ+f${d#oiXv#{%21LnPwCmK3eP)<%oEJtU{$g**UQ?V&bSAPC zKGx#MKgWBXHidOK)4=2@(`V0Lv|{~F`^(Q=zw_XKA;A!vJ@)^Fz)x($!AGDAjSluC zWT{KMqcE_cUB_`+x*`ro%4;NW1WP#JWNga9(u(HvPwVeONd#&6Y_VlGn(}hYvZQ{^ zxe6271(W9s=1}VRZ0a-FfT-U{yfW{Z(68!u%7ieVL;Y$#2lt$yiosjB?Gr&LrmfnM z2%SmbxY9OG1WxP~#hJuNhYi0-h%QhW(uU=SaUQ@RxrBCxZCQ4&DmFmSegQ-RM z_wCO+44N>>_RnqGnf=WF#DKvsMe7W9$?VyyH-jC!x_9eL5_B7?kRq@ve47H-<}F%4 z;EcW8h@0TI0?V+OpfC!#Z7NWr$|*Mg?T7mee_^hSl(}9&V4#~u(36`!$JNlGuVPo$ zW{*kWOa*(Ad7hw&DP}jAhG~uUxqzWoCg{1r7GIqBx}RDh63LOO_BkUg&0oiNEzCv5&}xwn{Qp z0>N+bT?tq6 zZt>GE{wQPX*B3O|GGm3!bHV=W1@H^_dwB1jFrY~(E;pt4P#KvdF6se;4)0zQbq~@5 ziyf4ODjx__OamNIB$z-kuOC9+h(FW7i2mY`fdrp8hO4M@5XF}1ctwFRBGV2Ljsmj3{(0{DRMa%O~hIKfFB~j0bqNn zB@lzCR|w33@bJN{YgaEqm$PTjuw`<|j_q4FZQ8PZSIGgQmV0+?C3$@Doaw}K#*ZF0 zpl8=k?OIZ?(V%|)FB>&$)3Hl;n%$D^IoMv%qbE$9GL6J5{#X54?mK6$_$8rZ$zn3k zNxh=~*p$gE#^LX*`ODXCas#BF@BUFMw&H{PHMc|mvbZ2|Q77HhGtQy3!nDv%{%SwP z@Rmy!W9NKuR^eL?$f-$!U#zA*mD7o=$Tgr5i6Dwz@f+8=&a}HC!`YNXjAudw-sA>6 zW^>Mi_|EWGvxrj!7X$o~4EPg8zgsp_^vfo0tCv$MIf>YBpROHRv*REem%pFHuXK9d zkU2cgY*nzJv%XlF5Qe`MI~;`=PWVj`U<;4Lul}(JUwd9|SNpu1>0gI=X?FYw!^4*-V0gn;QV*`^i!BvUI% zDBD8#GQxI7-!jqz+yuJhWFdEXU*9;$-UYgM>)r$LI{?dAN=ilfo0uzY^IKet-fVDh z=#atwka*3wn_nmTMhg#s>>`&@@viPaCVyjC{5PIb1PQG84fPuV;3R(qu-T;Bw&NUe8em)dZoZ>#XV$9M1d`&LMmcd0~b(s}rdRonK_g2*uNNgHAzZ6gqr zv6mAQ($F*Fn(34_govu5lo%;upb$B!kSI=jJXHbBNgfI~mf<&|=LX{UwyX0yVH+ml z8`3ub`~dv^p_u*6goM}lJCe5Ir7y#)d(2+EMLQ-`JngOL_phElx_?i}!DDB^FYEk> zW-*gQR1#Bd9}uPtm|lq}U_KuG(pg4hL1wN*=JjqCqS<4^0bk&z=>>Y3IV_;nf26e4Y_*Akl$vwBq~ z8)a>cTJSgKusZb2avP+~ffm5zUtvKjX??2-{xTC(1HjIeuIy`8bLvX-meW@CcRp_N zP2Uj{XU(VXP6yf?tc@z*9lH>~JBR|8l(@XXVPIhX>oXv^Xpc&2f}bNF90wFjx+`2? zp$6_2iQ)8tp$9n`?kweKM9Fw!6eB_#q$pKZz%QQMr)&$^Yke_2OAhSbzInr1#Q3Id zgrSL6Zd<=<*%DgHP5NQ{7;2AjpIbL?(uj(U`VAU4Z{4ADH`~n*7(mJ6kl|y#pG@*I zeK#omwYrd|SNd70#T{X#d2o5!Gy=&#{4fdp&Re_^{_Zc+e}4T6u=4Tv`}g24E4}y= z{51vI8bIZ5w59VD!!j}4lY`ivI8>$wenl`N3exk?k^p8wX*}bsAtsU_G@V5-M0Sfo zzJ}m#S(zIg9gcKoU1!E&GOpw=-ZS()$i;rruUJ&!Z6JWRZP`daF?Ix*H^UtVF`vaR zsaMQUY5{0c$*7I{9+PP>R~7I}P^5yu%HJHn@o1RQYT%r|ALXf68GaLg5y26pGfzhQ zIr6V87fF9Hr%J3*0x2JZkck6!iX@ge%ziZ#3S@TwHBxNRlHJ)W}4AgJW9`d&n#q6oO z6_jm}OI(Qyk{yY_Kp6HSc-yw4rm1t6zrP}?OD7Ojnovr-;74R> zL@hA;(MB-?0XQ5jhIVP_VvSTDMCmf9jG>GPc%W7kD?aFa;7S}H`X+jjDTAmLVJjDv4iPH41Ctslh&^f<9TV>C%UmJ{%5|!7#_WAv5XUZu6K6KoWDom5Vh#~=;sw$jZ z9N|Fo`9#f7d@lTk^bEl4#9X?3C@u34`TdiBo$+l*lTSEM_ zeargQ%NNZdnDagO9WtO-*N$zGzYQCFNuKD}O6}` zj#GKTqJ@hWF9N}fxnhUznKMYg^8BARbMC^WD}UU)bN|sZS8fmh{`bFsb-eyi{NqQn z<2@AuKlEIR4NwBW*aEst;@3@)((2dq6$NY@I1N_D=wOaQ4?sk2IL%lvobkk;JZu@! zXVRKOzlRj)6}}ik4ApLSTk3L?E6)~l@kxH(y=#{UcE6(yWIki-&z$o8sKI^Maj^N< zk$Qzdka>Z<{37nUB8&lK1X6-h#DFXC3wn$0coPMjM6mn~2Rc{4CSB=1J2as``55(^ z@i$Aq3OhLTZ_|h9eAI zVL=07xLnwg!7Ul4SPKk!5y29e#WJyA0qi+DfBrnGkQOcS4`(foGXB-FD~Bs#Mk+@F1T2>+Af#+2Pzn{IxqE0jp1Vvy$&)P4$M1XbaU1z{XcZ9!t&sx;`x2|9e z`|+JQflqw_r3*PCsS7AyxOfJK!Pv0?hReuU@}1d5fh#{@UTnt$#O*nHOlwqMxEL8n z*J(UP8!UEzbV~=)s+lOsggZvNsKZoS?%Yo6Nn&h7D#*QBweW|2-!%K;!*|(6kOe*e zGdqM@MYb|;pmJmS0G-;#Z@Jw9GS~4&)f#WTi-aIGlu@TP$yC*<1b~&l@NUNpUywD72L35C`ql?uw)t-GxT&+|E#RnKNm08+z+1L#Ck0Cc zBbZ7EVv}jEl!``_e9SBdwL@9BoYjNogXADHb?q`a1+=2PdGjvvmwlE=zj{jhQgkm_ z1cZX^ZD2E zj~y+3yLBe|+k{k=244~YZbHRlCjs267in0-Mvb%l$a9+$duH^Vj0H4ja^zDkT7&}) zf8*?@Hh963RqMCH-_sWzLFrYVcTd{fh@Egy` zUq;|J2u$NixBDgdyK?FLSyLut_)VG5;Fkj>BW=(s-6_HrtdU4gT_yw;iQgQ(l^!-8 ztopSiIE8@GBXn7`>=*npg21``9428ZKH{%XsR&Na6<4X8BL&cMLjp6h$MR<~`OA?H zdSf*zejWZQ8GiX4((t!oWCZ2+%18Em4&O9S7hae@TlmrJ{dgZfmA9(B@kXuB+6?La zZJQSMWCp*XR0sV9RRYtBBkjnLAl%N8b-QZTB!=ysn>KIJvUOA##Rh|P zm;{szuY$YsQwup$zd^>Fx+5fQ;gS4y;gKLPKN>?Z%<#Rvmdok!gy`Te7x7q1#Y%5H zGWOyQ7L$pQCtxXwRl!`KfjRf&u8lYxc7uk$u~#S>H~@_E41X81XqLW<#IOM*2Moq} zUKV0F_2qD8mA`8d!Q@{N{h2@0vm zk9=gGRofI6<}ju*`&QPdsso*;K=T^ZbA-HnU#Fdz zhr)y-b{wWl^(ygp3BFubsrg>L=A8$QoidX(=VFozX)3c}69C?}efv-RPd8}WQ5pkA zn$ii2_%GSdgnqRRT+CqjlhEc`h84;cjDK>l$SL3uLI6hz(jzkZNGd=Jde^kzCwe2l z;?)v>cuDHjof}t>zqkcEciJ3+d^J`q!QYLWH*Z7>FPJrT;`s4nMh+V?ptsqgS@xCu zZ5$oH90E?HU07Lnz%2{mV@< zul8Ad#MrfC`!=^5B=vda(gm}~e5U6!na{M{py_0o&z0ya{iIgFtCkL{z;en8@@5wS zVRWt?E7Oq08JiP+WpL8J3BSgE1HTdbH5zP}1gFTzeYW^W0Q>jzx4Wc_CHPC|HzTh}SV7-t%0cYbW>}pPg9++>gB*5eq*g7-%A(AdejAObN@^Sp zCco|0vrmfg!ob2%;)ci#6sDUwd!?*mH?H#wpN!k6V{Q(otcX9VU`Jp#T?1gVspD@- z94_4C1q$NyM!egoQKLr_3Pu8(i!~MaTS7?4VEzEt;4lOxqhlFCU}x90ZjBUzn9#3`Ub=)>6T6L0{b5x9Z(Dxd zu>Pmn!Ifpz^F^g&fTJLq$;82y9}qrP`@Ii7ZPdQ+_Y2qWJXnU!gtHV`7C1Dy+lVu0?>^@L_oGsOkohaM4d-uKr;hk7G?h47gLJ|j;$zlgA|t`u&ELq5Vz4PMsib}+;P=>ZLYMjnq*R|cc^X0NhXYG4 zMnhwkGN@qpemr;SQu6)?{+iNu@qEgIVF7cAEUc^7Z-HHsXq;0?q){~U$)CX}NB@?V z9wc*@E%R2bT>azv_3Kv79p9&I!;jvhi?e)6pmlg1tTjQn8+ zm@)!P3DUX^TefY%_}%%_PZ*Uu0Wf7=Oy;E=f#uBk<+R>#eGxecc4xCS3ZGo~1kuvu z26^`gKJ(fi5M78QyOdSHB?QKj=D@;Np%wVEC(!9SdmNP?+P8a``E+}C0boLtYoi*9 z#S59wBtDN5zk~YqME@&Lsg_$ICXf@OSCTbsM+t*mIza?s1pHz2L;b3b}Ig9)XL$HnP_j_{%R(w; zD_}*M7mSnhQo262(U;^{M8F2@C$CUwpU32f0{*qIlhhkI!gwB{iiTO{Tign z+52W zU!Dz~!fB!bbm!p%x_{HQ4GGXudK9Tw!C%muhVmBz!{4}$hLoL1sDi~1I7wi3CUkcN z+FX4_TaFg3+jokVGcr?rg1ZDgZ*WW3cl4-{BMi;P3ksM`oaJtY-NKC=)?5qVKyS`p zNURFZ6>!3HqHxqNaZ>;X$mMSKZx}lk3tHjp$P=J{h%_ut&Ln`R5Cxt>DkK+yVe&Q{ zB%|w^#H{@-4sj{zqRl={R8W(oMS$u+C*MONs?4sFX!| z2F5liTp@_zE8JnJY}5z@Fx*B3#b|K?b7eHrI(wE~4CJk)Hn^uZZ(cXylJrZ29P-yr z#zubKmyLJ9roeI~SX=kw@;T#rwW|NGcNM=e#AJ*tPOI>(1~`MAUPR`Vc~$>l zKO^|d0fG3{$*W_7gtu!}ulj~VHgjfEJK zG)u^XkJSsg&@ASVdv;#4w3}5N0Dee1lIj=w+Ed)|;w1!TL&^vD@31yHdF;r6_-lX$ zS>xNcYz7jWHq!Qa>B2eFCVf9{?5JTw1`p`d!)^twTQ)@wz+ZNWX-ahMo6g;Ac}p8C zwn9Pyo7zlsEAp>w{;Zpo4bDf>JaoLYyb#E97r6ED)}MCoXVWoPW~J~76?ydZh3j`7 z{)r5R-yZOxf1?F7$yY2x;7yy`svw?I;>yXNkF6rmWP48F- z7p|7s^%!E7_OiPNJ2vk@+0thXr-F|V6&%RTv1`e%!&mI08m_qMr0RE&U9Xyd9a}C0 zehYkx8`3Z2?<@ROA;?!XFN3SlzFD}}IWD8Gj{si~9PwX6ab%-{;E=yr@Hb^&AyKmR zWxQEtKdZfCk;>uh5$y=+TVX$^M@(LH1b+3D9GnQ8WSnb(@d^MdS)Fc+h+DWBxGmh{ zhQDfpZgxA}4c^AP(O>^b3BUf6CQP6N zi7}D?t^5PI;#c%e<^k_{%Ca&}nH!{Gak8dtEHWq;Eu2qW*p)Qs%}bMTs2AH8YsCrx z%;sqDH&UOMrbMkJzHkBhnNCED2uRJI(s#tee4|4A;Qy(=(~*&>3v%(7|UnnpI0?j{2_U7a!IprW@k61|eSg%k1DJ z;fmdElfhpvooDRxOpKQu1>dMrz1CY)rZI{6KdZPp@4XXx768+O5~BXod8Znz9PV>WO~NUoZ;)5WCas%Y7inT&@EiUX z%x3|d8PMckCH^Lj5_zird*Cl8O(@#L-=Ht~3q)KT3A;SVDN{^ee#B*H5r6YvBc@#^ z*}^YVMB9LEexb^BDlQt8dF=B=!@2vNch~@_>f4{S?mc2i-|spR{G~F8NUsErQ4qf= z`0EqF<|s?bbF;d4>q>8EcL$D+&kz{?27udi?AmMK@KG7%GRDa|VyqJc-2}D+<2(?; zjz~~WESAZknBywcst-kiR#?!+bc@hi`6kcttjbvS#!&c%o(}Q-Dt`mO>0jl)3j$Ac zOv-DJg1=@%LSII~ijL&T*|~uQco(vDoQYX;qdnz9hVi6@i|Lc4B^}vV%aSv_1Rb%0 zN!L^?o?b-m7QHy8{V=lcH%&hOSGX%-uJEO4^@!o3@6YvEJkDc5;JTkQ>d^1|1?zT@ zVnhNemG$Ke6|EYWgd+4_AQ#CSDAV7DH0p^gh3 zgF+-KfuDij|JMMn#Bj1-V1Cg27sBb{U838?6U@mf|eskj+B=s0StougeU?=1M?9helL;rMsG!Q9*wZ> zpn&OtLN^Z7@BRC3O6_?3j7{nd{Q}>o4E66_LgyD)5S2rAyoeJ-ndz3eo5JaJYnCr2 zLkRUdX4Hrwg9g%hl3K}j zxzB>*mtWZ7EA%hUGg{Y>uL&38*T9dN&c=*b$8i$sM5%s*v?;F~LCoDu5~p*T0+v&QoWiw+FmA`A2FPuGXBK!UJHuJer z{d%ANt8P?g6ww!21^pyoXkhBt90|Qy!%6A-Ufd4MdM6(~lMRns69+%|AT}PvfBrOv z^krZ^e;n0EkzHt$1od;F3@ZF*4P}RneFN#Mg%kMA(yx3xOMT|_sW_c7{)%2k#jls) zH-003ry`LnY~z;**SX@!fN-T(I$LX7hGO!qy!FmIY`{>hcK!DK*#Ea@mrl0D=$bOE z0<~SiE;k%%Uv3*2j%?A3;`#bB?s!FJtw3S~t;yH2X=TRWe^hzv zUk%&>8E7|?8oyME&)I$vztzFqh_ox|UK;q=pf@+hX~Vf#GriE$9>uISvSV~?#E z7^I}#ApQAfEaglopcB>uf*GblYdfQRwN}? zabXx-Vv*=EYw%a~Te6D)J^9R$t7cU(zgyYqcM}VZt!6&2UdD_x z3HsXvIE45SN?Zyi~Bi&mBrc9(ii@w zQjjp9g|P4q`tpeGbG#_yZ?d0*n#O;FzX`HjqIP2>0tbR~`U>e{0CQI8KZo_4@i%_4 zAZ0e`3RVBnPRrg-!<%VvKLI&=CO4xC_|0hUY4&z)`CI+{hTjevIc!j$?>d|NTxmqk z6^|tVC;aw`+TDSX&y2tvLfCaczuwWD5&}nG4j|klwixW#rAObvBjQ+>vN1wssxU)h z27!4fA0dVV!}6CQi#3i%$xLs;*cdr{fvq&=ZsBnrG3Y!Z;>x*?ovz7yj&~pPe|dWk zKC6l~Z~GfP&&-@T=cpJE1Vun{l$<0DB%HC_|y;oP&RsTB`*yZg4#1fdVmcD`qGB{JfR-#k|FQyFaqTC?; z)lzT8$Q8kn63hq<{$>s&@cSJO;0VkD!GIXt8Wg?J>_PyX-vffT;}hP@Lz{`1b{bhc zcj|~9t-=DG3@ioy%3S`=+)it$_$zv6^mg39?Rt$WS+}d=uqB~WOW`lTLjCLJ1i0TE zsEk_LPb{s|@U=G4&!mM|@tOOrfCZMFDS!FJf*d-Re!io5?2cZ$dId1DB}FAWsr>)g zoaZD>NZs2Xh=NeW@b^vsj4TQ?BDGM}k??%2^o6mHtGg%Ssgr;Y60p=C4jj%-TQ zK(LsM|04(3S%by8^Nb68P0zG{`!}q_f7kr{?t2)Wo!`>rCxD5hHlkUF?%#~P3hT2o zjnfTA>=cEP{J)96z&Zgq2%H(9hfkifWW{QwAQiColrl*lU`p2jeGro-MJPS_oM!?6 zPanqta^|!ykf=F~-uJf~n|6(OHzWD((vi5ppMd~G`9dQzz`~nBkIMeQEVdp$e~zK{ z(bLDo2j5PGJzX@i$L*C1l;JpBxqs)D?Edqrr{k9|pFg+4*Ry9B+i`f~`X!!%u|(Oc`a3so z-ezM;R=j}M{kz%41CMW@Hw{^rZXVHdb)z#<<3xz$^eoPbi)t6qmNpf@C$ah9DW?Hf z|5}0Aat>qVI`u)I-{OnX-HtP9#PM}IiHo|H*~l+;|ud`Xn29aZ^qv^)&T7tiN8c|IAm9)gkbe= zipgTIZp5(*jw3OXPGro9J`5`@Jp==6vFjbL1iqQbYKT_+jS(aJa`*!k8S z1PQTLx2aKtYmQy_82X`9Sc)5GA2$dT_b)ZD zI4|d@3UQ58BaH)^mvwz(uRC*^t%wd*R@EFolTx`ZieDx&T3sFatWXv|`o(h>u4q3# zPmu{;#sNsi3XMzn2W-*bU%I03)epycBa#*6#@W2drbo<;@b{|uO}vf|#AaT-m)Pg6 z8`sRAIJifV)=jnF9{qe!!Vu*=*e8^D1n8A!F?{$CP?7|rVCzVV@OU0iw_rl^rYJnd_~MT=4bX|ApP|b5m=Ad zg+cP#pRzvn@+qZ3NfW0$2ie*8e!D~QEEk72af)8MdhYD0+Uou6y0BsG*UP_J%mgxb z4gpxCA7PQhC6*#m489tWIe#bPl$trq3V1BC7c9h*MQ9}f9r%FNyyp00bVd~080gZO zyR3k>X8m_8mWlk{xnnC!Z|2j9_-;(_xW3HaE|1Uq&Kr?cP zA3k*VUw#+qzPF6D(E6Me$hk?GaRw-4H$ASEI-!|927n_GzU~zG zWp_)B6hYn!AiH1laycw^f1}jmQSTPMEHEh7w|y&HDX;o!;hbqvO3bQPEkA1h!TV}C zSN=%?C+Zg8XrQm1FhN(nnk>t4kSSm%xR4lPnx__?;SLO;fIklLi{DrNvg;rvIjlU1 z{tfG(#^=P}1Yo@>nf?{CHhHV~^*V3d9r*Qe4l)A&3BL{2#f+mFRf{xk!tJYMG?`=Wd>iRZ;&^!7wt{VS_>18(F|rAUgwa0mbPZ<1>6~4+6j{UK2X|3@)b#d}U9DA=6iGuQ;M76aq&9A`qkT zPl`fY5WrAoRI`I^teo{J8KH};Wfp+39AYj-`=-VcoB@s5FaUg;Fp+xl9%XN|$BBMVVzPP}1Nt6%x;%qmafA=v%zI5qXBo9DC`hTB2(A?XM!xmFSf^Y|HQ!*RMLx za!!V@A$%{M=YJp3yo#DeA(Jf})_u!gT_JNA>wTQJNH2~YuA7;7Bl;OypJ#UN>M&`obQJix&C4d-Q}@f~QZPydKO)AD|Kkit#bLV#fx`XS0;iHG2Kp<#VTx9(L1Ts@SZ8 zmaOC>|A?)R;IF0XyLIV8Hl+9+`Z>j~CQM@89$64`kiY0(%W!C7W(h5RmAqd?q$NJ4 zMXtBCPlpj&5xhQ1x$oTNa%szV-)x{Lbk(uCOF#Tv|NFzD@cg{%$5MjT=^y+H1dHEi z?7TpvH;Nv2H*47Y_t=~=#$F^FnR0{+_-DfgKyHvX1Fc3V0P8Km8)KNK*tm~zjUX1i zwC};MYf9y>!B=EU+YaoK?!U;2a`2ku*)-1JwPoZoNjTOeWtr+9htXMMtOJjp5 zq}{oFo0cDucvK*sA|TQCmCL|yE`0@U*oyOugid=U(_1Kvv{p={&Yq?9Irtm)XROcq zfZcQmvKeq->&DDpxO7o5N`GSt8RA}3XTV!C>T zr6`^73?^H1GM*P09K`jDHPDyGoW+Y;1AiO0=|3LE&6qr9*k^2vKxXeCTDB7*{7uQg zMqE+EYQp&O>6<>D;{;)JFuR1t7Yy^WU*92V<2%RDl)yCozj%)#Z%_*~&fmOkFuFPXzfc&T z@CLyQn&t53tZiXa!lZ$%hJ_(*{><_H+cu+@(m9z#iJ*xVy`li!qJ!up@dt0xtVO%t zW9EHRN{*y)Sk}Wr{{mpkALyS{2cv}1x1<(DdcRI5{q=QPoF-0g1M?{e`#s? z;S=YGw6$0kX6SRU)(|YRX`-A2a~q;AhzwzbGnh6ynh6uLs6kpBUZawy5m>)yRy3NG z$uvr3!QYD*t_6DCiQ^~XFSfpo%O(%#)Dn5&AJdwWG&C@2NI>!}X9Q>*vC4mEK`(ll zRv@ZPKvLEU(=su7jnxvw$iy-o0IN6%g2n~xOVG%YSHrgda4o}M82pAH{HWP5xfh%x|}Y5}=b#B!8{5NZ$4D?1@ad4G>FU-D}2<=s_A-=m-?&z*~x!6sJgp zm9zgKVRrj>Z-o?Jv+cqn7Wwl^W}| zmAES~J(Kb4j=xKnEJ(}lh5CniI1(Uu(pSq?V|w3W_3K?bB@|I;<%flu3%_3*sVV(oiV`%_L@6fS2j zL6+q*27u7M!QQw?>uSMk<8&Lfz{(K&$_e!^F=LgLlD3?%s(r!V{T%I$BPbk|HcCqo zzBGOt^?|5?ZRFJ#V=1KFt6Qgp-#j9P?ntDbef0HaT#OQtcW@mdwm= zc2!j{tw3sHucBdo#@vhqjutoaeHU`wtTsvCKwA;|H-$(@Rq2`(F9RiOA&R*(C$G=T z^=}GkOl#dl;OwWxilRu$27V=K#$0|v05;uhxIgYJ+~mM98COo-yc+#$^^HlhCrubP znu0NK_cIG>44@7)wrGsd@^=(g=Y-VpkCT%wPreZFEP zMvtI3K-vO)nJ^2BH12$lT%=ZA2Y<12)BeN9!qXXWU;+%sq<&zOuvlOi$7pvB%$oZU zqHS&Xqcn)2GuUZGqbXI3h{fVQ?PJ-F!E8Ec)#v{k)Xj;RW~hI8>4Y0C6vV4fd;aLr zQ<(h3`7V3Amrw8Ay>VGo;tqrW$4_y1^6-JZ;$K)1sAn(g=D@;eA);HsAQw~#D z?3}dVuagewhrj>%@A4P=M#?a7#{v9i<5t}UjG4J;<=XZ1-%S{xcMycNzZ@yW)J{B) z@y|MdDZ#;+^px54U;w82OClJTZV%L^@y-*hNVv5!rWjypNP55$_xwP=4t3t{?XVTeZinEW4!~kD*RiLnjIQm_P z+l1f1ZbsBF9&<+~bk!GlYnV;cr1T$z* zP5{0&IA*y5WR>^gjE36)LQc|qwr5c>9y9g7AJHSWrUBl(NywT&4?Qn1G8F=Ho8 zb{_;lIR{Whn_~l?kxi7CmU?m`S3x>1X3YtDmj=HKCJsxFmkT2tIw@d1v%Hm954{=y z7N6o)p&LeKIjVa&0azBt-CX)4hFQ|O$%TyTH=dteusrY+5`U#`;;#Vq_wbm9+4_OC zFngh7)@Z(d4&Y^`=ZjwejQ({WGee=N!x045;Ou^)`h!uu8lnraSYmfuxPB49@OQg` z&{X4KL!>1OrVr`ZB4QTkX>>C?y&WO?eF452qvM|J!hX`2JsH~f9yR;x9aXhy!};@M zyM7-lV`VVxRfiZy8CGXFtK^Mr%wNeYlEBdSZdjlr^}%vK!C%R%0;ZBNPrPT@d}p24 z=AEKB^VLH#9{)<+-yM@1Hs`1*ATpWZOw1L(MXl%tdkP|8 ziK=A8rHwBQj>@3SCCi!hV9wU``a7u zeb~PDh-q_|5{SgcUFOaKqSC$l_hHk7zbN3yKccL|36*aqa=tOl200%S1B3jkYG z{4SBtWF8rNW!x402n+5Xe-wJbpATL<<+*fC1R`ZpzQ0&^;&5eU>5eTM)~upXe;I&h5aJ-3jXRRQv*|Yo*blk^Amp|@bZ;3ELn)%#k>)5 zT=Ss$qD4k}IPMq1;w3~vui3D9I|aA)vFrd`1ce)UD3xXG9W?QT|g~%m3I{d}* zV~9WZ#v?2_=h>14IDt?`&Pg0b3&T@OW)*N7a<(9O)wc=2Uh^cMpM*J&D0r3Dz6Tcp zUf$X3oVl@%$S?TV0B{gkTND~NTSRb!ajEGF+w)2{Fbe>$!Fp^gR^V7GwD{EvoY5Hb zbGqxhc;k1J@BqLi81_L~1e%sG3PqT&>WbUQ z8CKwKrKg4L4m;`nMgW$@iVE(!moLZ{`SYCFaF6;WN-DhetQSRw&QpRD(?tH^Lt9>;-OL(Rk zyv}@xChd^F4gCG*+f7<`|7^mS3s^SSh;Z4 z{Bz(df$4olh1>V=-{SAE-lt&%Q0WmNR)79OH*}qJ#3oqx?^A`66`-Nz=T9Fe@_CoV z5j8zC(KvDF{+;%P<~#t*ZsmP?_3GWHpOuAh|B^L{32%aavuV~Pm^&BLn$4FxQb#A_Oz1aA;u#u%28lm~0QPpF@o3;T2pq5cvY>xw zvi?o%P5PJ5NQyUyZ+7jMPy+M4Qv4Ozr6uFD3kdiNa&i792_v+k z*Gwc^*rByWr|>H({)W3{+qUi7S$GF8GEBQ*xBiU zMN84tOSrp9^VZ#l&RV;>`Y78C;DBS&HweoT&<4T8u0J}LZdeckJC~L20=YPO^*&hv zfRWEYXVnceK#KbmV16cXq`n@X9oxn|V9(a)p;N`8ajLIRnMJpWK_QCuFZAzAG5X3Y z;WPoF1j6#}uRIWMCx2DOMCH7Ap7vsW_B)l4ez1_{IqGgOB@!rg;dE{F0qP^lg+qrA z9#Z{chORlv?f@`V7w~aFZS>SxH~}cQrW7RgvWOO~C@W`bO?$N=mQl>7wMC;?`3ye? zSaXXjT0}py$qeV26;1^E{_y>EO7J2{IE4`+6Y;t~68dc7ulhs)2Y;#lT)uV9+_8N- zu-tNDqd`F$R$`a+F{c1v`0H-I@|J(WT@IX9;?knd$lt_YR&5S-Ta%_%vv1avH)U>e zpWle47QpgX^&5O=)^V+Gu`J$D{hOs81?+JgzuEZXj(tW>oxAjF_CTV7>Xt369(V8B zgEe#C{)&pqg9N%A*2T^eN29#w6q|tEk6ak{#nkpfUNl9(j5nb0^Y6fk)zp7ubuQ{b z|Meo`ukNx%*H1rQK6mEmp#x<*Hhs%ram&Gguh~a4rcIeVVf>hpp@94M>CINC=3)#X z9yDBM?g2c7$P_085R5ojO#Jgoe7|Y|WOOoql^}pIc|l|6A7%rlfdz}cTD@T_+bvbF zq{E+4bMP>+eCMy;ppMu5hv|1jU#5@J;4J@>xU8M%$vNSTX?HKDEOUao4Qr>QKlm2o1_lY zyrfLb=nF|BhU%k_u^o%jmbLy6T$wt3d$z(dKgD> z-(OttiWrb_?W-|KHEP;^(4><20Ce?dp0@ZObBtDemyOzEcKt2Nhaa=d58_wggZSt36r( zhmaMlIfM)Rjb|nAG-m9EhWHI7&AVkT;5l=W0-h7W&;>IVAdDfqY%9`egi)( z8usT^G$ilWsc|Fmmzb=z6vUFb2;g<32d^bE+E6S^(9sCypduw}&h5D&dNa)=;1$c3 z%pTLHO*5=KF{8TF%R0SX!G7M*xE<2P2b@FcGq{02YS(wdlFj=MpCD@nVWtZ%t&~+| zf>$e6W{E})<8BI%lNc7j{KNYc-b|L*yoPXTtYUw5LW<{0(= z&p~1Wu&}pLA;L00hX}-Sf1VSkPT|)j7@9PhW8}$PK!O5O;0X~UTJ(qln9_=ea26j! zDAOo+2!GE+MNgP}Ua^a|z#d)43|FTmnc^Hon_nO*3#MNr-uDW%DlcAyIX{v{LM#>> z=J>~}02+N_atOv*LcC5KuPIye<;Z?rS~s__5b%AE5G=+&8dYahGO4|Zw52dcNK=8B zE8oARCA}2R_?u=1hdL9+d+)v|+Jiu>KzLIIixr%>q-I|s*Y|&0S*sjSGCi*HX z)e+>44|5Xx=R3{XbRRTk+Wh4RV5+xm*|N>;nh;UpM6AHlkAdOn(PKv`y#aq+t8hLL zzt+Bj4J=5kYAocIphgq#(Y(qZW@_uYVIR1;N7@&1v&6wpzNQ+rT zuUJ9sGYDR~FpO_bH3nZAPpy}#WVV*Rc?(#3uoDveJ&ZAha5GHp7p`8v{VVa$Po6(_ zc}agY%joeVf~(k7!7}MKup8GNlJ%R83BC#l=jAsXU%GcRKP3tifI%W~n4H6Qpcy6E zpBcOj?q9+P*-<2F*9C@I1G>JWOXB~f7uOs*LTZaAF8k1$@`s(4w0b-OSqYCf3X^ffd`CZa0bzm1xA z8!>aig7HIoccEkz`vyj54g6xU3Gpj?GZma-pu>TZOwX(cBS1eeo8XxMl|d>D%q}dm zCm2g8xWq5cmUw{9Z|`UQ$<278FHRH=HJp_7yaZrD8zhCHT>B66F-f2v_;2amk}NB8D^?LFcv6euyN1)2J#g6mho$pz*?`wZzM4&fQiVW zrK;}hATPe*)JRQI2HTLpnDMqEd$&PgVzE*%7O@ZO$)+e7-@koxgJE4#`d177MpuX> zXMw*l1i0U)CbuD-hA7x(t-21Kxq4UiiE}K661?+}QEZWX=|28CD{54t&b1GU^0RM&lOogof z$xsEUOh?Cwk~U156fM~ct?N|6X8)4CbOd)<)dBg7M7CuF#+D~*X*|{G4F|H=MK;Gf zNaAxBDaXNGnEW~2)JnW``3Fr1*M4*+H8A=IY|q$aiQc+Mq3Q6@Rc~D~W1hBoObMJ)b+*3{5OhkSSrg8^0S=3a2>zZxJCP(Lnq8y$XA%;(#UBlZW?zWhaXtFP}YGb70T*@7AvTYRN(-2!?J<0o3Q2f{T~peB;NC9tnU4 z^(P3cH+#GF1Hpp^W7Km4B!Zx)xK+#a8MBRoUMhcGG%sJa1pX5L$-JWAO_Ppu4tLC+ zGjGw-6>HfE7_*8g<;0quICFs#XLr~^!cBo$OmLy)nNpf$R@L9B|D7r|!1n=*RT<2| z!-otW0DS*`IDdJZnC@tIX?O12x?TTk@D~DOg^JCN7=DhzutzZ-(}1K~>B?YnOgJC> zWr>p-YaaT47@rNl!u-r`3#7p#e=8~|>}=!DM%xRBOG}}z_@y#E;U{>%@cho7gY9_) zw&xz*yLM~~e#7`INP-`%(_ARp=&Upq0nP3vexYje;lj<2v+7l3@Uo4dm#rz_Y=o6G zwdLBD`#j9(i^n$};E6V~et9OC&aKaM@%a1zWpb$KsnPu0V0fnI<}G;KAbitNLH@=l zNCP1wZ{f<{m-y>=$_>b>;0(RlmGlL_1>SnPvRgjGn;C!OO)x*d@pki$eTIx2H(_Yc z4sAYZ+o5yU?mc=Dtv~QHGJvz(qpa97!B>%WG}-9EnX_CCDhN~bzB~;<3y`8EZ5X5t z&StkW(MxwX+0F)ZlcNAa^-=c-KCNfI^zXH(!uh2~QCjLe+bOP`UcPh;Eal$oE z%xIgg(hI$>;Q=LYXx>Jri8(=Z6pWH-rHqAo;{ zzIgSMZNrrYV6NsL#ogW(GftLAN_dM0ImzLi8q4yCy!NrH+OiC_7v9rAYs!vO?`?|jTL#6x(ZDG zQ`4|i3@mcR0l5_afR5~Zgoe%finBzl&s=H)V0~sy*@xjR6)y&84R)IBe0v)pM*Y&k z-bG`-L7@(f&wfyR#D6Bp|Kp9fo3`rG_wz|}maJT37y}OAoqLGD+P8lndB9avG_0oJ z7!4CYs~Y|WTI&fEzl=4Ml?Y1`dK-0Iu%r;ZhxmQ2g7AW3|8$$~jEDdCCuHS(%MTaC}nGqR}O>|4%B(ZeLL;I;8cW^Pf> z24e%iVAtIPqqS+%whg-&(Q;#S;8pZy2d|i_<4!poQki$n+`q=8%3p>Gt5rL)y}7~r zo9HTX9V@OOvlb6JRsIA>FRiP^WME=$l=WEE+RjR>T` zXr^9s@FpUAsjd~o!PkJXyju0OX4=q<3dKw}$}l`Jz9{iLy(JUj=jhRY79CN&H5BjK7m;EPtaY4kNTk);DZymd$+`kiLn%tU-x^{(AZ1*`s=X z@&R)u1P%sge}AvUY*DX>?vc7;)*;i7Xx!w(Pd*(nXG8f>vv$5Gu<792VQ5b z54|XW8}g>T)>RM?H}e&1&MPpQ91gNnwDPHgA+VqN;y%j-Rufk-a$Y=lvgTmTF%&4N zNJq-|$luCpir=!GDWXM-GU1>{0B~(BI+t`Ae7ow_Z~!}HVVdSS2dl+(Eee@@CJ<~{ zX$Z`gI~1n0YNWuWbOvQS2*r}%r?6{dqE;Adh-L!3Ky>v5re~@aIbHgXKsH1m(<8A- zkv%MaYb(Ah8QR?l7pfb?{Kj7wLK>eOfRw)pzw*}^MM=t};>2QzNz5f|UnG9t3+?M1 z`7ZzX|9#A22okq!mAL%Z2-pUJH9-e{^?4Dwh5Tmo1?qIb--O@buOG*UV7q>|dE4#- zMouXKz~7Jqym{-+J$oQ93V1JDA#s+ebi&!f0USnp(xwSjLyXb)JY>VE$a|wN{d(_V zvSZi@{>SY(R$WSV{QSeky4s4p+rM4A9Q=lz3U!JF4Eala4H^Ju6NXVEh7TEp{>l>B~+SpxGDy|S~O4O8l@?K=O8oG!5|*Jv2Zc^_uI`FpxFq? zT|JJSI(O*@>azaEYV^S)wv2fE7!Xre0~d`|HEeh8*59os#46&gG#iEdefUs4422B= z$4vd(Z+L&rL$cup=0zqT09v{Y>$lw6tk0K3z{mjBt`hY&jCfA`wQHr&EBYvf%vnDo ze`8NU`KtvQ4=}k#qSs5>o?Sa4^wZP}!mbw0pEHvL>QTcub4FgZX&vfUVVA<6Qy;a5 zr54kVhjPhqzepj9?R!CKtBksBKKY~#?2Xoj8%YVbO1|M_Z!UHex1?pxV$rNj4g!l` z1aQJ{&fjA3TNHfd(4f7_U+&1!>w`vM>41qfC?=t-74et3)Co6VV&n=o_?rn{&P>oZ zzFM591_TG7GX{tL&6|Gk;m57owCfmKRkIZ^ivR(ZK%l9=;p#Gq%WROjmZHTfs={bgv{V>P&5NDAr3*;l`3Dst0)9XT4e)BGAi*n zU>pYN^adEOjm*LqlL5GZUWWykWW;2QjopM5!p3I#t>JKxH-l?nI0(!gaUB=DA*hwl zad*yN-#SAvA44ILWP*-}GAO(V0)t|IFyl8?A?Zi*16Xn_Gp8Z_A}hM9j#a^HxWFP! z5(hTC)I{&5O>r3(ptY-4q!L(72#1NT5I`+-^f<^DWHAW5CzgWwg?Au*K4{rx(A3qX z2aiJpCP6*GL14p~8NOIUQN!05;OG*3!dWO59EP~zrNbV^EP%-{YUABuR-s-%vYtIK z`G~0#LO%Ob@qyQ-R6?5ng3uthP{WEBXlQ=<68CNZIJZ?7f&Gu?Pl(p>tzV+1lbrtJ z#iQTgFEbRg5OS;T=;5R6p8!=)*Ou?zUAp&xT&Sv|0#FqRGRKZ$h^zLBFe{>>DTqZB z7P?g?^7241m9p5q0bJK$Pem^aYr}d^ke`IfI>hctKwQTwAuZXiU>lb*xy6{2&q;q2 zNS)QAiHE`JY~m3onbV9&kJQX_<{a||6#S?;uzBIg9v$0$@^SMI7@L@nF+sl#e_hpw zK-Hv%3A$ic6Nj1o`EQB6`mut)%z#OvI6DS_iS!7ApfxxU3Lx0HF5VvjoU31s@mTOm z+`pKg|09C0l)nHzXwOu}2mPZ_DI(W0lP8GXY9i8sk_2->C(A#w@-WZ9W->r=&=)V0Z(VK zZgsxc2FU@;)I=6>0(z{%=P}^1@hv8XG_AUqeg%IwVs&%E|Lrf5If>f|ML8 z#P7q0j~^>%p(&A6#42J@X4z`284b$byPr}ASilC6SsW=vB$7v z020M_-AFzn=>xysl)qubx=bARZJw+rUZo;h{m*pY0X+^0vk&K=vgZT&GOUzwLotMbQ|)0b}MTqB?CZWvo4 zsyWAR%hnlofiLuJ*RCA|<}hf?Rci=rQxHdMjW$mA0AQ@wLOAeitX2}gDGWQQ-!Kv< zQ%+h-0#n9iG(ejga9lOv=iP#@L zg3Us*B%`c8Mdkus6w){73ub~j3BZU}wJr_*N+hrx&6^oqrLdAPp;!E7O*^eJkz5{4 zL4_uM6YUslfm#G=L6r(%qc0#R%hpH^P99+S3sE7l2rh1tHo;er7a9cSSv*k0T;4c7 zz(6pX$D9K~v62q4rK>^c< ze!v8@YQ@rd(?<4e6(&P^gPklHL9%Y1cZa;+>yM%3@J-k8V3QW@`;K3-x%>#_6d|xS z!0&-BDX18rVXz~ZBgQiSV!wqH41I%R>|a{I(juIck=uk`JxGQ#Hcoql{uGqxQ6%cW znlZEcu^bvI^;+|lg-MwAi82L5**r~(mxmf2_N9LydgD2;`pMHYf&cORo|U?Ald&}& zX5G5uK$Z>QPn|t;lx_WXQ6k|`6|I^Id`y{<-dlO_h&#d@GA;|Q!U|_BD}@=if(FJ0 zeGr@wi3O=?hT1?^{J|JkmAj|Wc<5c{Ie2^O)M?&?K+_XQ-?}r{s&xUMRRtS-^n;#v zXU^+CQE>V)`WMQ(Ai|DacY^X8J622{(4}3QmWosYmL+iT7q2Y*{pUabPT39qYtX*V zEXg(No(sS?;z$V5!iCE_FcqfRB96i)r~qz^TiFSQ*(JJ^5nd43C4ZxLoIc-w*BEJ| zuVUlDL|;tXNiq=O^+u!jKknFT@Pt|OzgoE#0Zib+E|Os>S3;nh=a@&F{On`j!A6wx^Hn8?JV6-!1v*!r!QRn@#Y;<@ld{+n31_eRl!lh zw6z%tUxF4x*h*LqG&tKL^eVgl4O*LepEPj2DfxGKA%0-@LJI!k!Y~&JXOZh+SIcSe z{$OGuEppOX8sY?@TY9Mg#+IY;+1&*l1yxlVpmqPMd}+IPnspI|=M`Tqp7-TUi-(OI z`dOT{usyfL_?%Q{#+01D%rDW)5}q7o z!%Z{B(jOy&$`GogPK6AH)@V6#<3ZMw z-Y2oP``YGkidc7S1!Un6aoQh-brASMk`-a9xo@@d*4reab~KL|>ac3)K|JhstUXmgB^z{d{lM*#1yI(!Jj z8~#ZngeWg*B-Wvt!+3>h)l>R+_wXRNV& zoHSU5lMMpfc~d%6sNa~kya9koThjZ>oMQB|^4G!}+1va6G(W@$>vx*8?9^x2gjoy7 z#8Cim-?eL3DG9Lv*lPZf=S7nB2~Uh1&<;;?Wy4D38dd;`nBM&zmH7P6eW1`8{?!5e zC1Lj0J3s$$f#|xj?Hkuq_bN4` z$G!mYo;^4YNIG)kEz5U8Uowuqm^gm4HiN$GT!Hv)L#PziU-fSwB^VOwS6j1@`Yzjo zg?2r-6y|4hj|ihu)n;Vboh2}JWUFdPI<+!eohLjflsbASyx;WspR_B8^5el!Fw z@Yjh_bB^KsR*7>^&~JfmX2S{m+LdjN7$1&n_!}1JFhVPT)xV9>5>>-vG=Cny+%u3} zWh`w#s{qcFu#W|g!)OrC^p$bIMFW4|dh=Z>aLgPxu;YjC6Egc@i$DW6MY4524vD`qnqQ50cNt- z<`APTT*%-^3`~+&YKR=mj;EqbHzSYS3?7(0#P&6@}=<}V+R_?rNn zRIr!QH{sWWBnVs(`m&hSbW;9tn)oT?C~-RAFAd|f(O2JYG|-vDkig#=PfF??1u9ps zBn)%jj4{1FCJj^o+aIEzB~wW1@%Fx~*%hND1q^r-faR}o&>wdkGh!Mgm#1VeEWr{~;hR71_dz%(x6!w0Esj8LW_?T(*BR8YSIftU6gcB>!gdy3K>wS?pVXsoa3 z+f!yO)tx14*idII|D0(~IBErlF}4VTrh&8q<#1)`hB-sKV}Pc@9~Ni_Cu?k27;t2F z1m_c{i!_(8jY1fo6Mo?%@O934%i@zx5{)Th8LnUYi&G?irf>kW+_ppIy@_LP@EN*; zEgStl%kej}+E+P$`4F(5rYa0|Z@&FrvroG98$S8Vh0E6(fVGX1NfCl&O@F+i%=9%! z2pQL>9wBBL2x6}aB6NwhPnECkliywVqedV2pIxvS;e8-i|1&!;oH$%jx?|J&HH?;Q zs?bix^q?nLKNQ;#k_L<+wVzSE(4-vz?$W*Yz@ekYPnt~hGyhu$i$tSE%88|>Ggz*G z8KwlyVO|ouEjmCkRekf#`nBuUvIo-ob!*&#aoeuFl}9i?-@ujq;DNqe@Jn&72)P2g zx2fKGQvwHqH5qmGflGMcKC9-0me!EpyM7&&|9 z1-c;C-$HW_WYZahf zYtoSJt()NhZt-y|gRtDNYv7O(V?zHDq7Wiag_kw>o9L>#T@kr9ke1b9PT&OIqDvo2 z%gCIxqNu1P1uTBWHLqk`348|C5|sC15e$D5fHegxc-5^8mf4A!0vP_j+A`4#lBI70 zn_VRbr-RwTIKwcer-A`GN4pFT<`w{)@Eg%rtP(=}W+vxkdKSk(H?%PKn4-iwMbmTO zm(dJ>mAj+@n~JnSgLLExlYPfru;9x{16pH+OmigNAplH}j9oqN^TqsiIciT4y*$@L zdyf`L(DYOWqQ$w_J1OkhM7|7RBN^sn`uCs~zF-l)c8?YGi@yo5d$@NRx z5$)lFM|iss!L&@;W^*WIHl9Bx+lXutO>#W-QNh(0L}uoF9_)-4NN5;s1H1XG9Jt2b z7y;J#odDQ3MjunoFPWc_zxAd|UH{?orAy>sup#Vmbn3~|Sc8w(RP5Wmn@U#reyuw| zhU!5J;Z}GQ;hu<8!eru@ct#Q^%=734klHQ6HqRvHHR68q$Yh3$a)yP9d)` zPqW$KF^tba<0GI4?pvGofQ@}^{)b$$wb|o!8qoUh#|51hK4cKbKo~-MJGwt;?y_5 z0gV2&rM^_$x86bh0&b$OQt~gQH*seukwnqheP{>K}XP{a8A+k>cx{6AxE(X$8+cyRv#uF~5# zuU%y4qpJPxe6)7;TD2(?21c{Ri%_p6UpmxHMVd$)(cl4Wgw!3LpuakH?%r#_kP%}E zYoSdh4tnbJnMhp(#^NPW={e*tqdhA(iJi*u$j#In*<^r{6=qixJjqtTWfezGU;OcB zy}zmP#mFAAe3dIgip5bd9U)8}QC#ZENl3nl-Me~>&GEw_95D9f zyb|z|4ai%2bpsQX1SW)%KBWto-cSF(%$~n=E>1dbkccES{3`L6e$N;nQ7po*%Gl_L ziW_8Iu;tpS6<;kZA>?_S3BT?d6{{6(!`hy+kYj<8VT3-)`p|iZ7CIo|sQ_RN(70}M z{({wzzbN01ojP^um}Ia-re&t+w1m|L z=6autg}eoG6QVs#Z@^38@7o`A7&zg}FGlp~(6U7f%mr=Qw(HQTYj^gmRsgeGH8BbS z;IKQ(Uzn%@POeR98HQzDx6(JnZidhX{=!}!6v2w$S8dM;!uUmf3os?e6xdv60A_5^ z^12+bSBrDvuLR~OA(LyEio6X32W!EuQP6Rm^Ebq?_+^l)g>zs-@n{YFjSrH&0@xdV zc3i7|F$?6j=lG&=k)*FbAggge*1RsDm?&eEAV;kBN7XqR+jI@Ce1+=d8l3*8$@;zDexCrl4hr{KhrPJwc-D@zED#%bpY5-6++l>ESGjs zwK9voO36q6{_p>h6FC16H8_vOt<@M}!9Q$)`-MSSBYn@t!;8?Y0{l@L36-Vljzl4%SMQ60E_Toq!QlA>Y z=#9wYg`a3xk$Ii$XCMt*$>Y=TTyOA|w?MMBt-}wDrRmpSe~+rr>Su}0r4&v8#vG;l zH#0zEh0c7y7IEWzhfCxPd;cc<8tPyI0I^r#7k9la)Gt9NlrUMobiwTDgghH`<(7>h zeeugC*Kas~lL8hx!b1gIECZO6ygTQw*+=MRw48=yRV}86)H-(Rj4Pnfk|DYX!a05c zF$6AbI;iwM76#~KgGL2ALiD>P3PRwlIbhPEsq+b`64zQBTonU2Bya}Y z6fB(qm@6f4LU1xV$GbWfGwi;4fKxm_DSl1Au`QMk@k9JA*-t4vzKW$9{l2fHl;M^o)KTzRhb|1Qj1oozn#Bwc{zwwCt zZQ86=mjUDFt=+|L;by2>C&Kk|0x;HR>d4Aqs^cd`oD9-|Uq(Emo@tY1y4Gh*ZHU^Z zPu0N0n>=_-ohp-ZF&XO-ra}S*ZS@oX&dkEoNz9=9EeS=z**{INFAclGo~(|xuw>Sf z{*}tFg?7Q@$HclkN;CM&CwxkM{hgn+#F1ut>B^s>=Okr9eeL zG5@S#34!qjL*SDZ6(X>u_SlhH#Bgm*ZA}#^OR$>fV1z!(b4esV!V`}iIZ;=4_Tm*y zgBTvBu0nlu3&g6m*&H1M3duHsW5>*t~_`B*?`J2rq zPAUG&08IR|_Gk4k^PnX-VzyxFumhxtA-6xy-M=+nS#Ra1P&W?qarb z+G3`{S^QqJ)}49{9zA8w;^k{MZXpJmDwH@ADdw=xP2HL6ahWUrkzkxyjPRJ-FInj2 z1{F-j?|)yZH17g`y5>*+^vMH!Ant*5^ZL~br-)tKPx>lW)U6m&ao(^K!&jJ)$y>my zG;8`)D^XH~qkrGNy+7^Nt!vkA-Fx=#M=@xMQI4Xn?nr9sPMi`^&@SoI0C(_Hdve*z z)ren`61HyNzHK`hIs^%`Cm)VdX2BI-f3vl$s`lKqUs#kz=oN11Z2uyImLcs=2w;wG z{A@CPn2)6;!^}!HTB++X1c+Z%u1QE7)eGQy(tjCk@R!X%@A6Z_hz)y{)eJ^dG$=L} z>pJBpzc+)y%sWw z)~{+{-o{}8gky}Pi!{R~_!fRE14coc12_O%#NUj?`L_nd3BmbgyqXG>joxd~efZSb z)5j0#)wzQKf<)@#vlc3G@79UGeAbw3q!T0hW9q~YeJ|C#H=ZV zgU66J!*6(ac>*s7zq}09>thJt0GJn1+=5S2^&0WjV1y0?;{>L~1!E;z7^CMn?BpmQ zWd)oZzrKj_xR}3AzYL1zEjzG#>wW1dRi?cvjmh#QYWmgtxc%tilPB3evCkjWD<$sU`bhw5<-B~pP6MudI=mL z29NndKB`Z?19qcEKE-9TS&ANkXE*H6C~BuG?I=tyT!f*G&Z0)v;7#&T6!=J5!6}O7 z4Whi9t%w7o4%gf7fA~q~-h)SfF?-SSb>D7c@9H3MX;~@!ZffV$>LO#F zK5t=-u|oo5>|V8O3E|RTt%SeTCoWxg<0C==QNZ_q(^m@|f6`=h(?t5jN{;c}8f#(D z1=gjXZifD4-AMZ_5|0AHqL|Uca*}){;7cVAekk_q^ghBDL7hNMT`X41!CweWHPeW` zqH_^ck1+>p4xN~Ig-D&NvHA=Fh;G2JpZF`rz+NJsS+;=RwJTA-(NS(vPo82F@IgErk1*Oy8OGAYMvevI7Dy|xKS~Ffv{6< zw6vU!6-eT5u5bgyE>offm({}Qc3fw+`y9Z&fKAEXZrr-psOht3P8{B+Ye($Prpkfe zs2Ah5Ay#XP9Hgjs6@pLFEF-cv_^aUut4snZ5KXjAoXOxDIPzHNYJvV56AmpjGUW9o zBB!7gp%r^@f;;@qHa{@a!16dDc!5nXtWeCY(NNNH6ionQX%5I5XhA?mG~K{v1{VO$ zG0zH1v;sKsH`%p$GXWgp+C{PZk_l#g!Tv)5FT@BP-#qa*(KnOvg=GU9sVsK8VCft` zJ24}n(IC%?mDn|g>X5`h&!gTC2 z8lJ_>94Se!&CoBNJdpX``^U3;ILolp-M;xF7Pt$zGZt$%Se_%4V0HNDPcsWU?rOL{CNU}3}^ZN0#jG*(IW>dOV^c5oK&*v zyPfRuLwqmBYU=({c|Sx2^O+7`gRW4&wK|y(>^A}l?&=%%d9{%di`$rBENXKwH~LA$ zN1p{xn7y%5AFSH9Y0=nT9SuZj?Us{GV#gu}FZH1PQ&Nc|Y|s!mSf~Ov6gqCiJd*6s zfE0`}z|{v#Q@lC_U=f37LQp^z1#GoHeLG+9zAu=f@NzkK}+Byf%lb@7b|~jYOuPWNc&dc2fjqVx_*=J zBWp1dd-d8n>$N{{+@) zZIb|guedc9PH+~DtRgf!ho6^%8!^75?Hw2lcqMOC!tzaiHt@>Eak``~mga1re(f6Z z^_Pe$unS-0TJ;NnH9pHRRP3yEwgrWg4ldvq<%{uJ z6(0OeUx6N+@EbZK=WpoMB!Tl_iNEG=ELt5j(WQgW=?49}pn~!LYJo1|FViS3@zsWTpZ3UV#q{Wz z>QD~-d{o-$cjm0T>XmX%mIQ&rbNNk>BUG%24Y-8iS*|VzI*CdN!J%~ZBinpPle4yF zDVDC-O^jL_3BX8TJ}w^MDhc96Hpmx2(LrH`TcTvHT0;N>Rv@hA&Da~_Hvk;G|7w2+N%IKKV5F?GHb%%E-l^y5kiSEJFe5ISOUn_4O{ILs>DOb5pHO&8n7j(|~jCcWz%q0j0*0){dJ z6p<%zQ}Z%6AA9TG@8&$R^vBG2%PHpWtvlokyGfEU(uGNu&}LOHjo4{~bM}Z5__axw zy9%#L2VuoF2rIql<&%5$)N;7@+pQbdf55(L1l1)rWycB(g5hsf*^V6;psTC)@7}&+ z4~2@gzLl2lQw&7Hj2WwkkDOHhUci2Lfeqrx&^k{YXe`i`rOU_m=+tM_j3sNo-Cm0S zSOSx>6!nC(=oy;DElkx$YaQ4dSvXjs;j{To5jQP`k-+$jwZyXM!R>qI3_ChtBg6oG z6d&fd^FQxSdQ3ZO9T4NfMQok?8A6MyxNxkfQbF&Bmf zI{p2dIDx`naqjezsoyl$MCB{yRI}aQkh@}5W1QBwH$opMBtiiDz*}#>*Yx9dU3(86 zGkNCx<)k5Prii(DNcwg;q)GuTBC6z@9y&=-=(zwi0}`@~io?z8E`VaKD~i+2_d8%mvLG z;7Au4e*-(o^cH$BF49aC98UJ%;~;f6nJ z3zBViY}p^pdCnl0G%eCoZCS8l@E6L0*KnZ3bsXg?I0j8TA(oYPavR+{?9aSuY6VMT zj3Z~;wBU&I;98_W)I?iu7O?9qR`4;kR(779_Q8@~>uh zi)#@bCTUbL1Qx@=VL==^I5?acj*||?A*>9hC3mnl#W9Ll6|A$ECUp_S+=>GuvAio< z9u1wpcc@==cQn3ZLaP>L)+Av**7zKXovpi*8QlsZ066%YYycYYS*>V?HWG`K_C~k< z#r=yN-g8SefW-@DQ<|*R`&maTC}0gD`MOi$(nPKQJdB%8+%DV#z*wNkEhDSFL$|)e zCd^#CZp)tXDm|Y}k7!`4$6mtxeC-apGPg^YxZ(PZ+Ie_- z9}sCps0fv^Y{qA@T8G=Wabw-P&lbVOn)Z(u;R=SJ!C*^x09lCo{3(%DuTIRb^H=&J zgq*G8;N{bYzcXjut-ph%{Mwas=d1#B{_Kg`LkGiCd!(j%?~d)e_f=K1Q=Plj?knF{ zO0y_5k_nzxR#Szt_Gs`o^aC>_94CsJ$?HgU+47Mcnt#-`EAhT_S8Uw1w}NT@pdr2( zqvH+WIAV|K%{MIHTec4cSV5jKE@y1kRX&eaV+mgNeqgtU(%_daORwrlS}BPY(7 zw{+FoZz2wQ*RI_Zq7=Y!PLA*wpn&#CBmSs?O#olS?-2`+yZQZE=npTS zJcMv5G}!9nF8uD_yF<~l%WQ?D(yOVcV3DOmb1gO`CGgx5_5xM`Pn^hZ3}ePv4;lnR z-+}%6v(fp0K?A8WL^AN?DFj1P*FJ5@@FkhQOG!L3BofP>)pEWi(`x(nZJX0>hf9~O zTEC^V>gf3&f3AOED4A)=_hG1}VsJ?~{!diJf}hCPdUi{^e*H(*x0j+4_NDI;z(0op z+H5}mafu%oFN(areTM^osQ)x*GY~^pM`74p|0;;xngRA=y}HKU3kksVVd}@=cqd7Y z(x%E^7K|(f4`Q9kl&{WT+OF-}*lcjan&pe;OdCIP$bg=1GuSeWz0p|;=t$(SR|y>L zzhQH3;BO8kW+a}{PymbhhHM&IxPLn&0KZ0GOwpZ;hc+FF7VckP(gq!F?vXxd@f-A2 zc{faZf#2xKN&V^p&J55jNHhA1Ud=_(RKV$GNMJA0(lyaH_}kF=6~eiUiHVeHl^^X4 zi=s&x)_-+u2S!mnn}ojYs7kX~Kf0ZIMat$X+G zpHeNgPrm`L0XVGCA|)wRFriN~aW+%05LMf9m{}8lHM{0biWcFP<9MXuULTaRp&Uc} z27iNGJXNr1lcq_ua1mqMjU4<0M6J=Osas1hN6S=r8U|;=u|zQ}X0dDjy#ZO=leK`c z4`Ytb@XJmUg}2l4Y~z!-2mx;9f@saZYW#X+zW|Oesq9T=^9;a5u3>}6N=L+jh;ewR$Dl4_S8|mS~VfA%1M(M(izhh1&dq^rUU?c#cPdMurEnM@_SK( z5VKN?R&6_d+W+&(CCk=tD?LEH{Nrra$Fljt1=3#~%h#DLXk41A8T@6v&Cy-v5-KO4 zU@*4Dw&A}6WE8Q}N6bAbG6VwW#xevzMBAjf^`%ucUO-*ky2$|f{0Swbbq%NR=f_dc zvLJkb?Q8n?Pr+H~qM=<^BFOBOC${mmwVgttNuJJTHsR+ATxAKd>Hdko#M{&&`YPl>{N$X)pTNjYOVbNu*`s*1h4 zw&ASZw1FrJ#*WS+P0+G+@}xRXT=53?>(_tazyX7(GBj@D#K}{pfM71z z7x>GP1xuE#VvEI1)P!X-zID{f!2rEo2k>TgCS$;^`*!P|irUjxZr;8BIC}ES=X^iB zAS^#`y1OyvXGRX)|JUE@ZxN~dBd%Y{o-xQSTxNvbq+})5=Y-y1Fy7vJ^5`hR0e>|; z>%~z^-!NlK6SfxUSm1^QnnT`}aB8#4iCHl7J)*Db=($D~7=oYd&&KZ4`}DWa=PmuL z{*B5TtX0;mTrzLwq|w6$_4%~3CCCe~D57ZrWS!tyhQNBWpt$z=RZ#&*v~*3y8@&Q+1@6~EkD zbWh@ML_`wc(fH%;!>7!_M)Uc=o?SX2fIt0I4{+CR_<(!%>f=sGxJbs)L$T1HfD?d2 z)MZv-SV?LS*4W(f%5(7Css^D5Budt2u4tiPm3P{lY3bhVd9XFz>t%{5&J529Zt-;a z8|3ve`G*6>VGeGfW5&$6jKMjXFBb$Wa#NGRDLyODP0|UJbgz+HZrs2NZ5W@mKc_cJ z?;8Y82@Ba*DDXF=Yb;14aI^q)S}$mVUY5M$qL+r*AakU%-VR4Ps#rq9=nTLkdwtTB z?w(AM4FIO!Ti=NOn82Gzn~esq-eGDLz>bv0d10Cst=qQm)V=TEQB&qFU#|+L02Dl6 z8*$ikH6JDrJmpeY#L7(H0t*l zDovv>0KR}Vo)k)gSg;KrJzTzKT*oHw64li716-a1Mo*i+YU8#YIFOyi+}n_f2E?;q z)b@gDZFd=;wSRvZkjEOkx6F)73RCRgyRV|c{g+G@#(QPCkx0i&z+6am9b#S-1A zDy$#OTgu`vKL>y@uBjQ`3e1`;%)~}lNs**Hm_u4RQxZ!7oF*~mD~xn1;3mymckI!B z*qAS7&Re>YV$cwH8y0BRHmqwzFj-%?I5?+Qt`WpX%|*88qbuZp-QvINpN~oWM)2Ne zbrz2iT7RF&;5&v56H-9_5`70J$nUpqka%{UU6frdRqWjjBMB;U|4!ndStXZXgPzV> z8y^%Up{d6)V)#%t1?~@j`wti}z{zbC`?^t$gNNPOZPuK*i@suaiA@HT?ZD%^k<4Gr z>pR&ZX!kB|5~s0o^NzC0Bd0I@cA7_qok^)DD3t@U*46sO|e%DF(53~A+RM~ zXu)3$&ze?j#6IKnF#V|3K8Art{)YR7#9y2RSf4lR{rzg;>?z|$4DR2nTc@_IqSBR% zKN`#s95ipyqg)LNzyNP{FC-%^gq@`#bpcb&$poa(zq)@r6Wsf!#+^#wV*Iv- zzPf&s@j1Ria4tUH&tzJIzmnIkY+qLThWZWe23Yf68(lXsIMgrvb1-Fau znzbCi@jLzLe!9O_15;{zwK!jKvb+e*n_r}R^IL)AIJxNhrtiJ;zTsCT!~1qmA!&p@ z)8MZF?m?_RU6dHXG2;O+23z9#|o6nv;tAqk>#Qd%Z zF`R;|0>@&MJ2|!`0>^a&eA7_~UoV1VfXkN4O6hA05y}^$h5l8YE?j60n`nyRpl8vQ zP*vQ9X}X|(p|LSo@qkj92a*IfG}0)n61O80#5PX?mgj}Z`i#;IH#J{1TXwk8h_8zD zjW3xvoh;DlM{{1Z*@vZotY8<~_|e0bpT&l2il!#(l+k@#H*qed%hBfw9RsvF3=FkN zJ<_g0dnc-N*hO>xGA=*}fBWXmKcc`H1n%0S-_X&MXD#}A1L3{ZmQ1Ef!bNKo5l(sa z$`wFt1!#vlGeXvg7JS{xJX~hg|Q+xwO6KQs$Q|_g0DqH0rAJw0yc+3{(gVy+!-rq5dVCtwi>%~ zDl~au_qHuN_LT14zG=h89i_l>Cj}!YpN}n0G7>HoHLEPn84Znsl86{ma)2wonbf6e zb|T+z*0O!~fup9DELvsm9FCXu-)%wmZT^ladJ9wZj-9+W0003fr%lAQhu4tQ71|EA zDcE0e5CBt{gNgANrdgnI?C8OY@@-4U_v%1_AS19oVYeA_fccwRojoQsFZm8BI*Lid zbv^%k!NiebOWV0cC=|(DBdQwuq&Z^mr_6mDL zWHfpU{$_I+USOuFHv#aw?>B4JzFV(BBgRjiJs%_VhD}?y?cBxE#&ro{SeON>`L$=y zU;6$hDwjqQI1c}UqJ8BL`{x@k9zT41@1BX{{=J_+eiT){(SmqO3HhVK3*F}7Z@1Zs z;evIJkFjNBdD-sWMD_02zU4b>N)V{*q);-4am!f8;5CJ8VEBvo7u)k^pSj7~@DU@& zjExO}jnSMnd)}fYD~KuE#zKlllFkm$%Pz;>D%%6Lwr$-;M8TnBb(ep-eecQ3+?4+O z>0?5(*|=A7ieCaJ6tcul;HEV>?jqsu7cN|8w-YMKX*Ytp#B(#C7*Apt8+5&ai>Tb- zFGg(mOEYmx1x(8VupF0;x*Ji1(kdKD{}Nkp#<&9P0p!3FTu^KDm8E9LwTsjvZ8Y$A zC;gN?7uY^|p|Q_H2lVdNsh!aW&^9xz(v57HzLPYu*pInJ4%uR|i8+TGOfq6g06Wv9 z2xvXPMF!}OXy66}CmeUy1FQ)e^_%3c^kp4t%k_A|Z%l&DYc@M^H0fKwF9U&5k=U9R zjRpKBvr!J>ut>Xt&7RFrN>L9AVBa_9*@Rz(OltA7{jnK)y?T|uLD+yUN7)j_qe4rM z8QX?mv1!}BV`r8O@7=LYoA#Z%Y8wdjCIfU&wgMjH5^;?CAWcmI*nAvFw*dU0>G0E* z%$_lI(uA>NMvXAeaL8a9{hH#HQ)kUxmJa|MEpH|UL)K^k*^tU|I^7HA zgKOz_!JHfX4F=0zzEEm`;+(&tGHdyv_zW>Cg;B#n+^|l=T(O&c!a-o-x1eysb#SVuO764iqBj_u1!TCnI0h zY}(0$q6Q=Ym|!dtX^D!y7M0$kS^(>ECI%|zF=e=F7rzmp8Ov~H0jNtu_UZs*&3^O7 zk3Ytih1Aizf1gtOa`!2&GN_wX&VZ$l%?lQ(Pl=~CMTuxEUkJTk_1R0n^?u^7r)F%imumi0X7Lu~ihEtfH0g-oAO;?$X^v#(ujE`}1DhUI=2V z0C8jgfhyd;$I0ep??Baq%>-%YF(Yd$znj+mgLicT#o2zp`NwSu{2j&mauP<%sk7!R zpyDB`Gd6KwvTWsAs)@3HD#e86mz2!5C*>iFOININ-@4smN``y}DdhpNiA zEE?UTon?QpKetKS5GLKqUyh|V{|ABH<A6q<(^2{#N&N$yh%EP(}BvD*lGKP z?gqI`L{&~#u3{={D@au|liM`M_NyYUAt2n?tOUHm>YVVm6}^S^KLpY_kjl=mjW&(dj+ z=_1dq`izx>C_oD{qN826(F5++|MJtd%V#OLLa;jFZz#Jx&}BD!*%C_eHC|vAzwJr9y^)CR%`V4u4zjR?< zY&aGSM*YfQ1g?H#+O=zLjY8q)pUB{{8Gw~q><)|o4*Z@c0t@Ri{3W^o(*w&pqVvg8 z594#-mv3LHmBx%|oZ0JFFJDCL^XOp%`*iQrmSU65BjiBTMnBTvo3*Tu*ik|WW;n8Y zq$m@6X9gqbAC;Ylrk*tB) zKy2ZnK;FVZdLHuk-DVvIjGH-U)PU|C+IQ%T=vDc4Cknbp&z?Pd_3GWn9Hh@jQ?Jb~ zYQz!}5C#Q;=Nt2c_MI_h0wMlGK672!uW#Qzy=i^=4H`Cj;ig1$02@sdb}>)YkmNjy62Ze#E7_5B_OvnmJGN*_=Zl_4ugI*>(l)w%N>s_{ zYcI*Vs{O_u%WVLh@t2s0wrupwE*qpm4jVO|Qbwyc?j|0q_V`KmAppVbTgyV7{6g(t zVOwT0amrwtFaVXAf>L|tKqU5BYJfR`i9@f|4HPg)c9t;!%ZU_s9suUz8HPHmY+ybl zaS1SU2UVoGGa{lJ;++Ao^D>u341OM_Y+`X9VYwz9l&CLke7|vZ^V-$(C(amu#l8lJ z$^+FV{Z>}(-?@d|YIg0|N`lvxJ^S{T?cTnX{acw+@&A?|sHi@AEXrjZKN)V>Q>Wb1 z2>hO9W1^bs{ol^$)x2?%GovGz802QS%6Eo50VY80>e$$`eARwR*c~FkbgmD<_zq@{G9{A;RA-a&X|qgXTYOmGXC;Q zl5z<78+|3_)ttHw{Iw?;mgSyEw12ZC7QQnH{Li-ux;O}D++#W@48$E>RCWRsRMK&Ue0q|3n zU-#>8>h34Xh{aaLK6TwLt^Uf^Z5t^TxteK&sX}wuyzm9HC*kN3!-<3*DtSkZ8Zlzz z=-B0L>hv$Ic}3XOw`gCyGC1oIkW@iCd^jqq=+n@Ui(UP2?Wqe_uiw63yy<4*FNHyF z8-RtST<$7Dy>|I=`f90>0W>|5i!dFrG%FJJCXD^*MYsy&gi}N?s zZ@777ZO|pV62aajUxUAN${a}1X9`_4UWEY$3^h1_O#rsgGcnLMpqud*^5*zO|H9u? zc;l1U^q~a`ILm&r@1}3yS8xH41K5c$jL$hY!vdWN;J@Ur{WovXm&1@$@BvF;&Di>Y zLj_CVd|ae48DD`5&qypz8u(j8;7s@?27BXAk2SL%Ea6v!3BUTk2zw7ksfv94`V-wS z<2W;pqcbXs5tSekRDxN=oCPF{2pGsYgXEkgCqYC30|I7H^xp6AuJu&yKIb@d|8FUs zyU*_3RkiB*rF!;}zCEaodT$N9lDr_aU%&qS2Wo&O1?lBiOK_k@*$_BvgI;X8`T8r* zQ{=7Cx8DO~x%ckft5=`<20SwO`B&c<{no^ARkau0%T?2g1a7I~=HUq9aJHa0R_e%O z*<3Vn)s}#7e6j2b;D*20pH;*FH%IAWfd_2O?hQWP5Lyt^5}*ZdOACKd z^XhysR%q8CT%f%9!z#oUS5!Ld zrnCS4e*N+AKk*DIc+#{v3zn_kxRqTRj6)(MS^z`f(_ey7{B8~!=#R^@g z>M|?G{@6^=mC3*Sout1nxocI!gX+)k07#1-?}8`xFs4x`=%J^$LMNz>;n zcKi12RE3$sYZ+^)z zxcNE%?`!Izp?R~XE}>RLS{Y+-Hq`p@Qn38eR=F_Y!AE?)8SXRNz>;l)sE$ zVa-Yayl~#UxwEWjLpl*Fu@2hY+6t=erJ(omPfvgKZJY6#?;(HL8(a77IpP7!Qnbq0 z&rXu~dz`2~>bu0Mo04oxWutIBt_Cn{c z*WyMn#mhbz)0Zuf6YKD9$?ik>}>(KdV(W$hZ1~k}_dPRw+*{8-dS4IpFUl9`8{I2= z2MicUuKJ_clAn3*g_k5SJBHLKr3xg|YhQo$rRN4W{6+oV&wkg)=-z$%KRn2laRo5w zRNEHryjQHw-YL`#bGaQDNBjyYULDaJQbjsS;23a0Tx}J>I(tAK-18Da3>h26+eTmk z%%ck5g3xxCqhT;Qw-Pv(=t5vE)bdvp^CFwXu5S(9`Kv-desS5$a)3XY0}6#Du^6^_ z7WkrBj^qSj3LpkL?q5QplafT0_vy1N2<^sTV@Hj8vK%ac(#UUfdO~f0#a?=h%qK{gL;?pzC z0;e#iAu_3X&lNVaZ;+eV)xL1QLLE~EW)>H5DDC6{j?Wo;LV#!1_}|50_v^1(n143M z2#gYe^)ot#$Y+$Sg|n=Zb(wo+Bek2PN$p_jZcWtQq7K7FJ;o56m{=fh0M?hE9Xoj7 z=qE%$@7=v;*XDJ^HnZYiw+6%W%-IWE?a!XOUUtzyHOqgb+9gcG5E9`s!;t-O{By1b*`QSBJkzAl59b z&=8nFtTk&l?K(iX@0qW@1(^9sn~T=Z`G4L3XT0em9fRnBOE^3T3`R#=y^_aK#6SOX z@!PLIKYarHQizP`-t}w9XkCh@)(m9phOYcz=`zf$^JdSWpex%1j~@qs*_7ecmqGCJ zxDX6@COg=P?X_Ve$4z>F>Z}FqYP4a?&bj|_j-lT+Y}DfVX~9;`jH zY6Yv5rHhE{o-Tfeyzt~B{rgt@g1PGCtz9P_ta3M9smv;wWw>biX!>O4AD*Y_B)Y19ybj5Rzm4e` zCrkmUqE^DD$=rX_>XTk+gf5M@x72U+uK;$Sq~&`vPMlTC;c&vz8UW|I4YuA&YvXRc zg(;HycGq5id+$e{ed*Pgo_L_AdxOO4tn%#-eFsY4N2t{n9|=A7Wwr~E!6k7vXflt- zBIko2f4JD5F+L-JiJ|UA3F(24KIODNp`bT1xCP*1ZjPy03Kx5GqY4wfWRx_os?74K zu(&)J{i~$Jyaeu`Tc{WG7DZf4(yHLbT;3*#A*TRs2wFfIJw-~byP3|$NigKNm!6}>0%6)5$*sO z0+VOPZW}N2W4%9b<;ER*$Qnt#UM3K1%i${yEz^xIU|M6lA(q{isMH#k=5s9KF~Ak) zmYDuF;abcwZg+$H!Dpw~g}Gz|gJO-z29Ey3HV$~tsEb5lU{j8qr|Z;wxddD_cd=Kq z=>s({^#uQd{$=->Z;dJ>{C%$YHh3K7&Xnzx8D zR;!tQmVLm6wd)Yan@HZ>ff-o-?k0wZws#+M*uLFVu3Wof$=qq99=V(NXHK%?j}y;{ zEoa<$ruut2WzzB&5OyMrpN5!WQi3w5%cOwI6k1(>Tlc;XKJoI{Df20Tvd!4kP3u<7 zc;nG~5Wjccaog>;vh*kX3Oy?x9s69B-4TdTu75pK&^1V1WGyq3HbY8B{?+&qQjlb= z6Dci|7JyX@*Ozhld}jJi0Bir?xYKJg$9VKw^XOa#XZ@2B@yOpR{_x-b^`HDFgF!G1 z&aCz4zx?f*>pI=qrF)PTU!&tCEUSKN zznuEN_{&<2B4>0A>?Wl4WMe;iAwBS$A9Viy{1eg9-<&;l;>bP|sQDo`taCpfe&994 zv}16^;);hK+ALW-pQ6q0zcXP1>+vzHp+PVyNw^Az4K+I$3NxXB-zl>f5THlxkUfV! zLZ+JcV_yzRzrfW(sbydY3-!W&{aq89UB1Hq{txDyA7Lp;L|UI6Gpbk=D%$lV+4bhw zqh!s5##)3u2~#@A1;Sj}g;~DZN)oYgRf%gx0Us+R>R1b4j8XxAfjS1m0+}^J@JrOg zVTy|5{AJf8Iy71BMg4Bu&W>MZ$XRxBCDC!1=9d!IP0jf!?-+aa)MEoFym2R6f6!~3 zMQW2Vp$vUG&AWCM*q4s-uNQ)echLb`05$~){_0#o09%C8Flbe9?9k;__ZENIuR(KC z341Qy(vJMCb6mz^>B(iVxyUW!j4>yD(k4SCx=R3KcUupF#@M$x|+0xm^=uYvj7 z4jGptIX`8nx#*ykVaM11T?=)2tkPHenbro^DV=Y>=fPJ759rmy?B7_PThiA8ZI3^J zr{pPu6rO+KMF|`gOy@1WQZN+&TfEy6tAVc>#8|TXQt6!N$PsT&5IF4{&=IC;*+vf+ z&=y2&!=bo7;uJYTsf9E)qCq=wg5lic!DqByWeC1;7kZ zqONK*wBW6JI5&x@X{^xzxb5AE2}k}G(HkY~y{fj05DtKI(0u6zy{;+vO2%K!6u{Qo zp(NH!uP{H0VzwuFd)$~|&p+Jr7V4EXoxe4SIu4?C>6_kklIEZMEsYy)*U2xAPv%w@ zq_GLzWwGxFU{_iq7*od+gP(hK)VuRmZl)sRan{^KeV9v8%36K-wKnK;23|7geHQhb z=VKbwq~?aEf*2;^`2Ei6lV(_?;xFVRdkE=*#TjEX)@Gsln{_NnCuX+2_%k-jfVS}0 zOXgbM)fDjHX%j8U|Agecm;f9U5mBa=B0R>9x)eE}xZ}QETh^N6yJ`I@D-uqJzjJ4^ z*VMvgxFuIJOE1?!Nl*=Op_@1F%q}szDAhzd5NWy4cQ?^IYuQ|O>ZGCf-)7O|(gLYm zFb6RPVH)Fz2}0v-IqSTz;FoEjxS_7RlC2Z!(AH%8&l_&;a?gOLUmy40Tnck-LAO!; zxqsIz{mr_H*Je|~KY-rwH!3)eU^MWb+>r3v z>&cJqdEbD?h$I;G=G*V%zSK7*&X9qC;UO`SoXa`8fa8XGbwqq>dTUz0l60hq`bk?hg(27AiTU@-_L<#)_m;CJx~s)v#Yz+Mrbp|#JuiwK=p zjY8)hNq8KlDJa?qnX_$YL!shP}-0EJ|%<5~-6)>FD;9f7f`A zXbOvT(8Su76ktLd8W*t4mBU`5dJ~nU`i=bkJ%3}t6>M2bdT6xfPup1=_iqE>X4uJI zMqSODYe(FUH(UHIFPFdS-`W~0Gy|orW$2ZY;Mhh&{<`YG0Y1w7rS|;Q z6P&-{Wh~KNh~ENf2>d1+dgl-+1kKmTHx7Ii^lT@k0h(gkX>+MLJ8vH4IHu2JyYI>G zPI&9hQLjJU@6PK*t6jmKhhNU=IejBN-<}cnhQjT-i1RO7FvK2o`|TvQYZB@zf7#|r zKLb&7c=`tp6v0nZ@Oa^B_NCu{6h z>v`?ZmMXGb0=!JKc=l|mxq_z520RQKI@UIx6|0skp-4TfO&l@`5(XA&N`#t>v zeqai65Q()6A-ZGt;g3Hfe8BK$1Tep(zdS+kKeGz+r>^U*-|-hG1m!gd$}0wF>rP5F z{J-v}l~lFMn0na+_~_o9gxT>kZrteZ@+5d|-@)EXJ9q77{|hd$O;h-L(Y!ehqO97< zNg8V&Atefk%8DE&<(G1k;CG$rVTa8S`ogs&@n0MP_$NyU*RBQLh^?Zt!hXp-bs2YR2IHHFO_GHCuYni9b{U)2WTW0>ALr>?5{{0>9MJWK>Lj z_wCVU9zFCxZ`JQj|>parF(cw#{^TDS3{hR9+e>Jz1_5Llc_Pdx@B!H2?rIBt_ z=nHpK_o{?mseW05*0dv6mM$fmj$H7YA$U#c#PsAs;E>W1agMb{0n1(}xeU5|C?+Ri;6 z9rD5x1BjaHd!H>)&*GOnA{tk!;6?=FEg2FEv5w9=0WChnw7H#Kl|cq zZ&*&ol24dbXV{c<*jL+b0%c%~DYj*7F34>QSCXyGy+$Gjz@WFy1|8WO`CBi-L55l7 zt%PjXLd>d#8&h(9Odl^_t>Cu>V5u7xmuRdG`WKFa?k36$>6?fw|8OO|w|t%hU{?u3 zr1L!lacS?pZvZqFXBt{<{sPpfiT!GUR3a-Pd@kh*muz|A8gulGH+zoUf4Oc-l@L-M|0nCm$c( zPteKMbt{)IU$J`iilvJdXi}KXdS=c%;-E=9B1)DdmF%amk<9|A!HHY|zB{)waT5_m zuq*W>v1Y>G8SlK@>n2UgPCA)*vb+&moLtwwsqz$Q0sRs#reGaWdj{Xd2= z9{I~v*ZlLQyLt_H;^ooUZQdI8bpIZ>z2Gl_TTD4fSASuD$b9J4{*11%ogdrJf5uwf z5Hr?4(5QU8{3S8hVehEVG@xp3@t2!^EFb*0e760APqgDSj|aXa7-@fo`+hajkAh#} z`yc-yfB#Eo@E`O9U-2hw(0~6sM(8`c-FqKf+du!xu+ih+nK6$jvyIz!A3S{gB)p+a zBfAdb`=|YK`7*(Gm#sbuh<|U5=BMX3$GxA%;*Iug0-C-;lafvTVai)KS#!&{ate#>-HR4HNEqGrO;m-ZZWV=H}<#-q1tc9t`Zhem7 zBgY`xXQ6(#;QjyT<5S36s!ZE+-B}Zl2~|TbV_g20MPqx^A&$1a; z$vQfn zp{N;&$lrus`2_S$$o`>&`}W29%wm$r`s_cQ@{`&3Nb|Fazl+)Pciv2VzoUn~MB?xL zy}A){Z@{3Py4AmGk4V4B?dDePC`}J7-KJia*(RP*SEfdLYJVoEFfmvmttBQ)GLj@# z_VPfMpK4#(YuuINfR=tN&hnX#0RFsVFMqHMk~-w#^U0ViFwLcK{r}-_JSlMihroV9 zA#kpB!_b5;t=*UPT%}b^x*gU^5bPBQ(y1-z@xPM=~p5Ju&pqM%4TI{2{%UerYVF& z;SvcI2v#>RBy2zl3@d>10v<0-Sn{2kRt0eMZmiQh0e#!d&%DpiDQ_3PH2%IJ*^c!w zIGcIaSCp3#mc>!(yv`Q{!qE6VP0*eR&QbyJ!i6cfL!Q9ocdgUgf)Li_jRu;t5 zYZUa4nyN2RY>+rt3UIW;uX`k^mzl4b1b@a9X*iAqR+%s-@?Pb}dCcNpojHDR@7}}5 z$VOp*qK$-IEn2pMq8sz(v9$%USF?!BH7sb&It-FD{DkEGYOKW9t^U{y|@TeMm%V;zM*ATMDaVHX%}R})^y39x{vWY{6t!dU-Y4GZL)-`O7xo?`i;Vp=4&feV zEw#*z16}n4;rHF2Fe_jt5h5E$u(#@)6Q?a$v3~3BgH)hE3)U%96T z&G4%aSx>q(i2N=1P1z010h1@O=ip1vfZuz&5&7(z&n|7VCp4|&J<(Smv8Q+7QQnau zQGgWwCI?9XhrfdM?hsckTv|NCTAu0uWv}1B7uRp-%iu~MuK4}k64d_6NGMj~RspQ6 za@*+J5x;g>8`tHAcOro6+w>H{*q;+N80~qJ|q7i`jy!Sfaz*fJ^aP zTcF$SqVU%TDg`T93lIe`VD13l&@pV5nev#gq~whZ9#Oo$5ysvIz=gkDhUdIR{I;>Z zEeKlzmzVjeHbD=e+r?yw;+&@Gx`A1cczPBrBy0%F=}b5Me*4W4FFn@#w(KBh$Fr5$ z{@;y+*7B4oTbZW(CG;7?GYKwuWXN{uDu2B^CuBYtNuAl5Py2-!obyax-w>OP{5`OD z|Iyx&EESx=k);vz(+=^f0o>8{TKOhhVe;7u~Z98!M;w{_04a4P* z?KJj^Ay|cim5b)joIK|7yD7iXp)mu=EK=vWh+h@Nfkl1`CWA~%nr|tL!4NhEOM4jB zEFQ^yajc^j^j+8a_Pg%x-krQhCaBwQH{sEBvB(p_{LgQf8%}&?;VzBQ$SI7KJ z{1pLMY5zeJ!T|V>e?secwb(T6(Nl+sg4>EuM{ZB+#=@dmzy5G;4&k1$MQ*jCZ#ibv< z`{4pUhfj_lKFBVI`}Wa85A4g1nq2QcNb(R}^*CUn7U`CaYv>Nt<0zIlt8(A~N|Bs* zC!~1Fn-h?~Yqsw@bnMg9U!2oy(@IwkVBss_gY-cTx;B=7jR5`)PO~6jtw3@B7)9NZ ze@Ads^yw!>#-d!&zNb<^gT*S$#Y*iNxd3~Wy}FBi-{+1dLaS>0mCId%zGy~I)8IIt zXg-oQDH`}S_6q*i%9Hv~Lf~S3W`8fUv#1<``bGSf4JzIlH{$gepL-?r3JjD^P6zuv zbITLyAFZ2o7Uv!bY_IWgFQW-rl>#DWoZny0VQ@P)a3=I6>^2|N?ci>Ffn&kKIN z!L1^Q6@iWwQgLFHj?x8Cpq9&sVH~M#w?bz~D~cDl&dF1Z10O<49s0>HD#VKfVP*o%+%x(VH4N1&xsFcCWre$QZ^ucL)o)Zi;) zuWqNCyBMVv{<6b{u73A|5yJy$xvB4;w6hn7y+yraRO1HAHti%ohx#0crSL~?=}MI7 zsn0Mk-+|}-1*-5iVN5YYjx&A)1Pn!q9$ypASPl;DqQ;2kmw>e znDXGW4QDT=>vG#WezcP#Dw^;Y=3#d~I?tvMUw?V}1X~8m--ElitjF!UaQ=K}nwe&# zx`iuinI%h?kQ|EsH3?D$yxQ!eUAxIYLM33o+-{@_Rf{*QUX7=WsGX@3U+a4-vB+u7 z`E=j~hRN#@zyV->0$#|=m=Q|$QP$An*BdEVr5!r@_p1Cr*Ps$u6)_3jamQ_U+@jG9 za58?cg=ZQr#2*NDqzA-KJ^Zfx0T`KVU+O#qRgKRq^y7_91av;g@vl1OKaMgV>=Blu z%$E}J_4~E;Dsq$f@Wg$YK&<@zWA*<2C-&#G=->bPZ>Fz58L7pGaggk?bjuyx`aJmL zD;XG9HS**%Ysf;3m$of=5&BreXVGKrV}^3Ok5;iYNc zvSHG1$`{?7sJQ@nCgR3`YZN)Chzqy+bWaWit61oXDyuTj|OQ7gN(QnjgbgOfHh(mA|kULVFGlmE_+&1T)lz37Q}@cIVp0?!SaT zuOdHd39euFT$uRgh}YQjh{)$|`hGi=9ZvHrM%$%xaM5&n@7rTb%e^xDB>c(AhbDg= z8uVC)g-d=zu$Xs}a3O!;Y`IK%EC45KczJX ztD;Qa@|;;k-@yEV7K76=uT8|OR5%0EPH{j zy12wmakmKIP`IEr1a5aT>y8i{pqB3~fh+5Uy&vuwi9GJeUryFrn3y$y_7eZ zisCuauHQsRw69pXY~h^g?~Qr# z&Ks)y<*YmAXz(fkc9tnK1Gr=X#dagQT^H+#6lARYt)r<&b94yI6t?D$N_{R8m zDWXi>Z6b>CtMA@(@EE1ZK0U+6KlT(1$~f)854(CKMjn$%%o{A*ShcZcgU+huZ_Zne z@$6R^SiT5<$z)<32Lah^8p`QfmAg7dG0YOEge}%xpxsN80Ak{T_ftoO(j1iOW;l^g z@7730U1(x6u@C;Tn=fhayAB*@k(H?3XLycPL40#5pxZF6a@cD88`Bi zweghTXOwIT)0lMRF&#h7GS!2Tm+%(>oOC_b5*N-VPnfUwH7g8qi43oZr1iag1uro? zlk!x^%lAx^z-bof0Kc^2|BV2~6i+h(I=fV}_b>Ft`pmM^x||Eqyxui`@OyKCENlK^dyBQXAh+zXpzuw? zufkXSimQl6x$8(M{LMfJ@!B0@nFuQ?UELN#vIIs3!`~KQD|i2I{AK}L;OmeLd>y|T z5RQqoc54#9Zkpt!d8nBZnngo9;_?;R-OKXiMnWyGx%MVD0DePb#G{W<=~)8XoGU_q-{=Idp#KeEBPUOY^Qhvpi8K9U~$J zk5Y}5@GDoLcK+M$xC;aH{R190z7D?w_)Qx)u-x*2fwYHF!cPyKG;bw!6Wy)wAogck zgI{KiQk2$t#G)Gzm}0%(fM9Piv0_fdVu*d2jbF7L0#`hI1mhUqVn~*(ZSsx~!I+hk zj6{r$=Ig44oSxM}ZorgC9<+0Igk>W)vwx2fceVTAq5U6jUc)XmSQ}lsuo2xXHm_Mg z{;&LHf4p^@HYo%?pi1G|^=JcgG=n3i1F59&cm9m2lZHG%@yRmQ+l@LN zi0O&4${6;YAb1UhAxY~gXv&++RgW5i@`HuD+ z)q9Ydv}4q@)t}YBg}%Auw*FryEVmtILEmL3m0{?hRA?{em2Zy>^)K-_(Y z4;?xF35h*1mmp`skQEfsix#!|j0*&E$bEMFG#5owYnsCW(3^iP1fR z$Bdgeb?%bY+xC(2e&#IvztoPrx%nII*Ixvem_!k>>q7i32=(s>rQ+*^ zzhG2jvD&x7x5!_22eVoYw&x4d_iJLW+&24j!y8YOo*ysa&gFCDvgL~969Jl--!1rLlxV^Bp4JL9l0w(pNKQadKwQVCQdEDRZy^Onv{Ix5teh`fR^0MUmMD>Fz!v7X6Qm{;iyEdu{8nyw3Vv~Dfn8drRFx|*<*vN_iK-chS!OTn z%2@N<+lGpiKL^gvaWUl~jB&H^GQzZgZd`8YX#C0~HJxX&hU%se^ETYSXU%*%_vL3N zj!*@dz?+?$*09qcCyY~v-kC9V`n)BiJF*ec!i7s#tXzYNUypH_`Wu8_;qBeNga6|w zBk*b~0(d=YVFQJNmM@q&`K{-=UB@Y8tZ`DC5vTagG*GO%nsrg8o^#j7&Fi?2Le=Y= z|5d%{M1HICzc2Q;`zs;F|8#AXZBAjivrH0;Rj|%UH)sO3LAch$Q+{=5hd@Oa%U>pz zOf-MGl5Gh2#R-D05+YL<`NOWw)zGbPQasD~UUnM(rR(q|(si(#sPJ+BT75G74T8PZ z@b?OWui{A71MX@1N2fb_4}9vi(QmVf5Zf_)u*xl_wkF6t`%Hr)u!NBnALnO;4q$X8 zI+|wYEU|R_yMQK!!WdHuexnz)vEcvxo?o88E&771uCGdcDLSIE(x9c22^1zY@T9rv zr>T2ESO6Ai04#jwGLXna!q8;;!Nj-U8cVsI(eiic+U3!OAcIx2#3?Fpi3GR0RhAT7WWX+P zeQAAOjQE}M?)WipysGW_f!;mX@V7mF`Tc7zPhY5a?b>N_*SUr}F~4|&TRzbC&QdD| z^gtRjkct5soy*+Q*qXf=cW=H3w_i5xroH{q7u(hSq{L1$Z-3A z;kR=5|0RC`aJ;~3V4ExF2;qEbzpf{yUU}0onWbl0kv9ssjM#t6-v+=1#qc*90FM}& z1f)LfH;CRL$_o2(5R43N=MIL!w%(;-knaD`ql2D#{^i$(niLC-itFocQrMVi1|Fl&>zi%H~>u76~lS-v`=rEukXIU_uj zzn#D30ToBEPqKP=Ydrr-YB0&bQ)jq3!36E9L%)?(IL411@$#eh++3VB{`^jq_KLri zQQ?%IuGn-JItc$85NkPB@SC1b=coId1AKRnUiVo5+BCDr9(~Lb-T|)^M*SuTpjXd( zdh{Il{96m)?;bV@BD95&%!HMg9o(`%f5n#KIP>)WLQg}m(5XmSX3ChNeFO?)g8uC{ zvVUuEm0sP8F!;Cs#XJp}F-`kI(@ZY%oD=PL%3%$BPSL5r0DpNk&+&k>*q3LJza(7j z+_`;&)fT2}XPJfhV8-+rvlc94-l0=1cHdrWPMQJCM)8&>hP~UErM7=)wj_#yyx$EQ z05H1*FPT5<-C+;ia*b!X1GCBu#X1}~6|YXr&z$lO^AKemnG*CNWe{@_FOnZ;3(>Lk z%FydOF#|F6h)8A^in6m}7QVJl@!RSKCMc`0ve2H@6?2{CF_6Q5xw5Y8|6mL>&uF{m zQ~1C5e>0h3OZF4|LbNu|uivlow_dw+)BTKg#{FBffB*ZxRlQ-a>X!s0gRfNK)cOd3 zufFz%Tkq*V=;h&56Q4!dZO-$WwHr5YCd^GEG*MCnB@**JEkkZ7BlS{eG%;H^|v~#LqU72fN)ATC( zBu&kCLkLXdNht-*{DTH)T1hhkzO;07@OwjPypu+(8n~FDyiVg=a;po?tf~?NJ4ua=-HhLSoaZ+|Uj^c(4do1rv{j7V3FV8v9nHdc(knRlqO5 zMy#_0E<8%yl>t(*r#7Kih+oNT>{SXqfnUh0Wl-!E{w`X~4yy7N26MwkwIWNlpo3My z)j_NpmP{lSOr=1hnf1c0Vsy;Eh|{q=BY?|w>t(!7s22GC?owR)LK)mNU($L954PUI z3%SEv?cpd3ykG?7N<-6>H~jg z!ds(XAKdqL3L=&@SLp+l!1l!23Wdu^VN@`mGY~XD7xJ?DbR>`od}r4lz3%Tn;Ng^6 zfxw7h%+5gA_Rzro7W3}Yt7nfMeIFk>ZRJMyM>^o<46MCBJN>D%Tyl>HCqcTPP87bj z9~He)l&lP83>z0lBK+ts42WLSczFp@BFgp>MK%a-(b}xu)ojgY#PdsqXSa?O#8@K< zZ;5?720+k!K^q?P*QrmA?%Td)%a)DnRxX}DcZS*Jv#hx=eL6J-SFi){lBJ7*fgA8{ z+p=!Oa(C#F3tM(j=n5B4gtOu7)=h zGav8Yf_si_YhM|E^u@fe{6T^~a)Z1RWk*$CU z10uPL+!)O#he1b3LxnX&myjikjp!w>%@IO=YquX@BGaj~+2> z$WV%A&RDQ)4SOyeqO$Xs-cQCfUc7LP7DSU6Zq<3ysYq$&|r6jIf6ts9un0l)B9 z(9&`WjWFXRHjdDVWRT;{Cu^8pS~>hU=?JpNbh)>d-d@ux0lOfkiH}P&GP}>)vXe zKrjCs2Mw!Wcnf9iZWPSb3D6$v$jhM=Yq2G-Dn+?!BWoEO86pjKb8SiU)~m`p8x7o; zpQC|WLby%{8AkcS6B~*=o{|p_w2BdZ%_gHo~|j$ z(AQmmYxS!q1`SF$7L~0uMfSS)o?1Mt2isS$#ZkY3TA)n{ZuSNa=fI8P*C+>5kE+X8 z)jK<0-((#n=BkQb*c!lQ6LV?17!WU8woCwfy=*B@tBa}KVk4SS+jR+;#yC6KY$c4* z`gPkhW($vPH(K=cAqZMryKT?6-I9w{zDCy9XCSyV_G<>W4NZL*Q!)(=Tbl#Y@-Jao`4XdG;MYO`Y zs~63m{r>O=Z>9FJ4Vmg`^nxp{Ir{?G@dS9Fp|e2FczFqzd1vN^;z)84eHFh_c|krT z0CwpNz)-$^J^@ug6|Tqn41rU~ieaq$%>nS2`RjfRgj8aU4um*yJXH-U)to z%`Je_{1f&Q{zLJW#sS%Pe6+Sa&R>DP$lt%4eH8w>0YkuBc4A=GN*W1&oW-j)0^ozkKKcB@kH01tszI>KZDJJMznJL2 zO9{9to%jOlfPl0V$8r_GuwWrz+!RJ+ZQ;15`HC!6(drBrm#cg$7Y^!Sw)NHYTr9~) zj~dGTQ8N5a@Mbo&R_1!Pi0nq^Qe=`PurU})WGvE}q(;#@ znJ(hDB>fJ3`PuAu)cx)*w-WEy3Vf~|v-I226VmnTh26WhXkPs);csJbbM7gl#Gz5B zQ#4-TuWnx3%{2VI(Y&2%iySOaa>*#Qnl5X>KwSbb;>gM3xMJ8^4#Q!h~h>O z^IU|mpJ2`sZ5DoE{K1y*XqX4&+5t51l$&X}SCwr`|H4z{Zo5_lvyTf&KP_f#MQd7= zt1vBp$;bWfeDy4_$&{)=+S2wdZOhuq*^JbCUgqO?i`Y%`8HKXmDYJnM#Zt}H;v^Ht zj~Vvz;QMY(M6ADh87GlZ_6F|;1htoVSINc1n7w(530n1=b_>-w0PwvAK?C3?h8ee3!a%gO(x5H$K1 zc|efL7LrtVfA}GL$ZlgdKrl|U&Vso!CcN0Y69O^KliiH@V3Iou#DEiwVtm%Uo3mZe zR`Kf`RYviZPFWz@r|Uq?FX#u;{0lz8g82qqzePBNzfjPoY1-F1vYmjO<#=Hy6f#C) zOwa~liC~hDtiquWSS{h0Z)UF$+%HuAnwQ+J|L1mnA|Fm{nP?}oIMWmYI0RvOaVp{$djlcn>o(wV_cVvUdv@=pyf*o{2ak{`1Zmi>ia-Lo z5$Q$PlF9S^oH8!ha>bfAF0kDPc;lZNZLnU8C&D`8Jm=z$-X*i?2&eRvTCWWb(}35} zBS#KV(;N5iT6QG-05jUcd9$Xm8Pdc|6K{?gNtO5E6rY?rXW<8H=pDNc9y@*hhxY#8 z{~-(g5{?j7jU*obi1|Aq3?(WswrAs~T!WVMUFn<5-x54^@}&IbXj1p;%P$F)K=6WK z2ps;_b%Q%J9FHmaFfD2JRH4=m9m{j^`$}I7%zO49JS2fRfk(0CABDd>ae%VrAMPTW zfA=ofyBU)M;up{FY8n~ultG^s&o7%($MbvV?G$?{8$!2rhI9x!ahjkB-<(sRoWQjO zy>W{g%3mIfWwv%JJC6W{F|H%4Cq?G!3>LoVULL2Hw^zLO{MeJyTN~oq*&SsxE*ii! zX=M|3<=}M~oc)>eCPQ>IQ#F^@YIqrSe9fhmdfaCnd^UMG5P*D-thWwpD6z?3py%19avhY>K+IT1gUJQVhz%f8a z0Q*SVVp>ZL2hUXn^KPS~ZF5NO!$g~{85mr+U*mrjjp8$=C@u z_-hy|q0hK~X_|=7pQFw|^sWl{2g0bn`|jL1%+=@7ISqhew)_R$Txr>h%;6=_7ZURz z!k10x)YxPo`4Bbvtrc|U4A$q}o7h(n0~-NX0WcX{Go}*7HV6J(*`9ymjlQ zb;&*=r8!hcj41rwgKpRkjIAO}?W;xeroJ=s;k${xa#VR)ngdJgv-bocjXPESddB@F z)B(y#&px{lG9~a|meKOpAIsrMYxe`@aaKyIPT~no}x`89j4K~O+WJS935|F84z`J6|QAef(XXw zoPROcL0|rii#yB!@igCX^WA+OdiwP-lcvtr^}E6)4-R)|fcY6oW<5mU0W1z3K8Pdu zC}9LB#2Q6F{FJuXFImgcV*s$xNi;68J$uXU66*@P0e|}gJqsJOnZz;tevUuHrk?)n zGs-ri3lEWyLryn)4+|Q=1U!JlM)7oL`!qBwH#<7NS%{>6e!2y^%=fX~pZJxRj}Y#`Q` zc#Clso8g-+e6bB2a+5Epf!JQO;C>F75vN2!8I96eRJR z#!e0Q^&3E$q(Ot-8JKMehYTG)Qlspf;~L9zOwYygjNuvj2D<>*26fvvI1G6g7pzu0 zbB)I;5aubttTN^b1Y8fv{kMbCq=>l9sy#qw+W=>5As? zxhi95+K^WLTL|f=1?D{ETEmYQq`46*R(VM%}5Tt%Dy)wPTF@Xmd z0B7~tnR*X4yfERfbtv!Y#WoD2m62FRGq;RTEM38dVD)>TZ?B#`dk=Vi;?m9de^D=o z+#JQO`7rU*yrxO zMdCT8a*nwUdO6SDq!|%Q%mA9VtW>cW<1&&HC-?t7{K(>CSP0^=oh~8(Lkat0)F8n5meTRP%iK;%VkMJ9WOZ*TBKA zj-H5`T!Qvph3{ASn2}PbrZ{Oa7Gt1|`&ToHO&4jd=|<<} z@HZ~LObNETe2W!?UPffIn(BQOCxl8`y=8X#0 z>`bs#^e-`1LY6hmUP^v(9%%XsrpvLHaDSBZYD)XG!?@vZ%KC!g#ypO)!y51&$c&CwSdK#RY8f!0!^oEG_e?ce`#OYcFi zjT$?4#7mFg*P~nP&k?{y0pB0`_U_%Q*S&^b75MhNw-=^oqGm1F(W(axe~b8Sf}W>f zd{+G0un5*@=ioO0{vC!za7zwD)DZ?s^g_WbawRnl6mwY!j0z?+S~n?z8%uPF zi;e+UpRkYwn>H9+u*oeLs)ogIEQU+-v43qU=ynYDQ+P;YF=Cb{%E$6o3V&s_1XhE4 zr3&^U56a-T3(b9>pJKq)1YW7Tn5*JGMgki?jtHKtZJosD5;5{ZzdJfPbOf*ysx2m; zbYSk68oucynuUmlbt+aY#R5bGL=%W;<)toN?v6FXZ8uT?S_nVVWCR1?2kyi6(PzL@ zqvvnlxrZ8mOcBRU5K)4~?^A+jSi{5LuP6`rwHwX-c)_YZK)1B>nCHGa3x;9wd4$T> z%%z|==IU?MyWjB^#4Izbub|>WqPUn?0s9(&_tKI3BonqOg&ia!iAg$lzEVYT$m{iK$y?-}` zN(AtRH7lq*`Tm609w5`pv)tge4lGVJXFgL`J^kRVpS94OdGhzkr z#6G6|2fZ|M!j#zyV|rdoiWjb5EYE7+9jtMbzXymQ(0YpFk^o=u3w{zE9R9|Ni!HY{ zy9?ds8jZ@ng7kn}gOTU&{~`hi`U z5`WKPf&65m5HLI&M}?X-hDsNWfy*fjV)ju9zhbe9{EelZXe{1kqOc_-#VHb3^8n6V z(HcYa(L)EY6{M`!AqWe8u`%!A|GhAnm!g6ZzeZje`i%CqfGQgzmo0x+vEm>kV)}b; zj~z~lB|N`(N!~LAQ=AejWs?)UDiY-LTIV(OVf@ zt_pwaL*+H)G9OXgz*Pem`&BssBDkETa?&`G=2SAG8~*;z{Oq|XqtUO=@|INy-uLV7 zxbLYUqlOP3`od%Pb!SgH_QYufuA|ni-VWxAd|P=Sk=cj~A2KnfHrd%iCDE zG6V)#P01`MTrIvr6aq`q+>oN&YsuVj*T-@rR4%uS(i-hcD}>d&kWyF*;8L;!lKN;B zzyYZmn143#Tj>gav5+g0)w{|5EtD>=g3crXmxB*~wL^RVUHQwFr7u6!_2%q2Tlgyk zH20L>7BDlj(mR3#`zC`TvZ~2wF&m)d0BDN7&4l2)?(Wv(9>dvn{12f1RVu6`3QGap z4+8h?|M+WD)^7U{^Wi}(V`l%Jp~#*XKAWvs&zvT%#1tgbMj+=`hJ(`Z&e3>SoO16h zMrusY*4$$u;$um z2nozn8nF2Unp2-6+TTf(l~%GcZtTQh^`|vC3Gfr0#keIa7%Eqx+`02jNMMvQyv(ov zmn$i8nbanOsRLlgJ~Za(^5-}Jj@lV4O9hXa#`hu0i!WU!Omly&E8RA6l~7UiwaLuB zA@1rMI1r*qZtr&AV=qv!bQaq@VtHP>VIA8`5%8wzdFReppFiAvK=>K~O(zn+)`%hx z_;jML%pzj7_O%WTB``nudAdRE7xW;0{O_>(5?6l_4H_pbTG-$#qMZ#=0>4o2DDZ_u zTeo3)USrtveENWUKd)W6gz}41-(|IH?k~fdT}IxULXpx%%a$!$wPD-t!zaJ`?o!79 zXcOZI)^F$wh^zP4F3o|eWbs~;V06lo&+u3A`wL=H{~WtI(p*a{`d9jarYg!>i8{v!C##pztx)F5xkUHB!Sc6_#O*?`STOS*6|k*Xp{uPu+CS%~4BB$;%8BIC@10hTJzw81+> zgpNtT@T-JBkAC`*etoe^+}*YNJ@@wNP16Pqd_^zq-l*S}{O#TMeyz^{82$U)3j&w~ zV73t<#>lOHF`6du3N=crHt0g&xitL1FtlZFE*50LtS`3|q6}68=JKe)&OQx{>r-CI zXyB~z8T_V|WF4krMR1zN=o0i4ky^kT-OEi;+Y!I<`G&fY#ewl?vh+u2Ubl(aqF$k| z`c|-xf6LEpo++pW#0`8ae~TP0!CBF|0y_wgUiM?SJMkStuL$V2LY~p%oJ+ol1fKZz zo1=!m@ycWO+;*b_$oaee)|sK{+tsC04Mz-}2(zo1x7EL8YA@+{mBFSVb-@dKch_#+ zK`?%WR)w>KLSune0^iTRHqVY*xM3&ZtB069Q`Lw0hQ=&H`bU|BoHm^=amszCgU+Ug z!Es0MG7~BnfD^Lvs21lMqXnKVtdXjN+{BJeWGkP=Bn-xZFt6u!J{taBNJtLJpA_If zdT`f9!k%aGi_`1glfROfla^WagJoDvC_A}9{%+mqF68X3uzD?lL7TH_owjEb1tNI= zKB^X=9oBxZXy*HGz1Zg#_k?M`Fn2o13jCiuTG;E<#mUb34nn!#@HayevSNT{T2Pbz z^{+0Ah|?^qB3DknDEtkQ8<#HZEm10fjR}jts|z>3Hx(ZF89S*Sf@)re1-eAE@LD7* zCS&HJznGZo%B&83l`wrKldbf%Id$+2a-e*lOqqC~wLM2r>r=kcx*mV{qZ3u3?;lP2 z)$z;gHB(>j!mbm0FWlAp!DolQ`7Ze7{I18|4}Gbry<%XcDxcbfwIk;$t^kAC#= z2|SxrXUrB_(T3qt;*;bri#FC>^r0-%T&TrgL8oE4rZ<-4TWrz1$jo0djrc&~sgED~ z=*WRR#2{&c#oF<~V)hW5Idkq}{JR^mZLlHq^!Fy|%5m(E8$WUKjM?)R5~|I9(VKVd zJNDVx@BhXAT=`2(LTNfoeo+3prX=yn#z;T_Q*sMQf0Ae_+|MKtu^9Lm0AqPR^=XNL zHpmP|v3eN2%rgXP@nTCjAKVXr_h6zwfY9BexTP`Nkiuc??mc*TvEm26du&*t4{DUA zDSlaVkaa}LFG;^voV4c1+!^mr95-s{%g+sdw11zNo^NLIs4G8vLwX>+*e+pjrd8w? z{;F+TkgNKy;uj(nv#i}MPX)k!Wa&(mLA48t9{M1|C_wUt11jWA?=F*Bo!0EThFo#c z;LAH11%A9k$HR4sqvensXhphu`L6_SftS8aYvI=$G#={ko+~PV;{?XAU9SDEj`f_S zW)x)%<)Y5XIaV$*c3brIt21J34l$}vruy^f$9i|U`Ig)7>ejt`ca_k+Ft=&2HwB=p z{PpQx0k9kVW;-OpuU;R@Cf2H7*@5(x8Ad)QdZ+++diGt=44oDRhn|2`m7753RKzOJ z7qE)tx!RU#0JgZ1eX0$^4SuN;WrZx0Wut{$257hiTj#vIq-$YFf>dJm_e$1PU99Y*FuoyZKX4>ZkmsH4#_>5 ziouyPsR3acy6*k={2r969X(?B>reLS(%BVk>7D-2`C0KNXwq?#l?jX)|EYfwRwx?y z+XAq$SXBngUjTgPT@cu)c0K#-fMml3j20ef9&o?@4?Zzu+KR1vl`kY9DO@nNF>jJn z0e`Wm5nNJ*i(3IVC5+Uu4S`9>D=5~R%c-veIl%m`cJtkkyOTEspR8+!V@ zG8ccDBt{x3uziJjpJ&gW`RpWBpLcFrwPaqb9#h#R>K$YLShDaRDKN`ctXM|m-ip<0 z*1=!o5Tyv%fe;3-UB90C8$7nnqSnaY-DIckGErsi%BAzBP8#*ZU7hf$YH9{Eo?>SX z#!+Svmp%?QYz$6N=|uB}WpLqipe z(k=M)2>6rEN!Lf~`coIDny5}}9XH@0mJx!X|4Q6f`QhmsWfHKDq?l$7*=aWOZF3ZS zxQQOLVj8o9@omigE&8`iP|QzympS@OkG!_<_r{yMbniFl)v@o8O1p9mxn1n64196< z?$}O742v9`zwE?7@Qj7ev#2&Pp!w7yAfa3x4hI68=tJ znm;{vK_6oDr;9&d`sw12F6+eENn)uj+IRx|9^A8o0AQo8*0S@FB^RenpR)w~Zr;3c zH5qENs3kXHyk4lcC%rdi<~+>h1ZuC}ux0!1Lnlt1?O1>V8}x71o91uvhf6cSU%zvy zd4)BZ>QxYy@sK&my-19CvYL&mcVuRkzdd7q!?qR?o>u5Wx4wfBiU+PU#?iukr_1*EKhQ9Lr zQ;$E~k8+cBr{8qmEXC-2X|+F;EBkX=0bA%+_*!m?TUsP=3&7!Y-XEq1zydXR6{YEb zQMuj@S<7<_CSNF1y^(8g=4HNA{#FJ%3~EcyrHht>PI1P*w)s2tAvxj980N0GoYrd-2nWkkgUxv|p!}b68`?U#w9y7Rq_d9Ou za(6d^o0*15?zLHBqtLh9=TZkSPuxrD?*siQ(^2EEh<+Y1+MNcg`W3(MLswjB#THFE zO;UiNsVJ4JwsOm&R=SC4C6--DD8Abg(GSOZ*h_kP3SR7wq+)04@a9 z{2NE@Sd^_$ZMAY&2J=uw@#s+4u_{j6)7i`$Y z{zpWHu(D^CF$0OoQq^k?29u|bE$*GeF!$xx-(W=+#Ham?RY5_w9KeVh%fT_`ru-*DhaV%I{QuZ6eer zyM+Dw~+mJNJ?6^oXrMNyGkOWn^&({>&&ciblVQ9ZpdHS9wsris-sTQ(nYi0 zANO*2y>xNl$N<67XbLre@-B!6BOdtiQ-Sx z$jHjb4-nd}mCPB6m!98+#gPD3{32F3hRiuKkGSOg&boka@TNF+b1Ty-J9865wOPw4 zO!PN`uxxxlg0W;cN6g>zP(94nkt$|=C4EUjOFuHH$=u&~e-R6R@CNwh*suEAH7w~o z7FPj@0=vCy?}wfrK4IFtr6m1s+`P&4jseebmw)nN4@Onw+>uh1;y8xl#7bG60{&7E z8k4NC1TNxY{3sE6kj^*(bC13g$Hfy1dr8W@$c`MY{meZ|nW&SW9COd#E$i2l#l3Fb z25OxxSu}?#t_zm0Wv}OLo7b;gx?s-K_ppdDC?~!za{M{>AE_A(fO=1^hfhGwM)BPRrXp5i-Gb5%SYq2 z-9Ld)ZLQ5_@S=P{uc^GcdJw^hvf=^Oh_+oy;Fb-#JjR18bNB{??~`r4i5Nnny{&iE zWjgk(?-v2CY$4kE$JjbI5$#I#Sd6WDM$;;efpnp-s+NY1PBfPixRre* zvemy0e>Hy#UoXpIAoV%4Ll?;#%8sgxt#IW^{*LltFG;6rwenoK>uv1Pn45J02b=Nj zhO))F90nIhF9SXNMfMW;tm4&2jwFvJkIT3*Xluw0fZyRfzH37X=WFZPd>6coA3Jh5 zB{=T6osD9doFjR;rZE>Y6C;4MOt%1B7Nx}j>|~wh>x{+f%rtKhbbP=7*xfn1b|V77 zwG{w<6#PC!dyqOD{Rz!_V(8@MTiE}|$V`^@)Zd|iAUn1-&CCkwKyz27p2O@cfQ$Li z?cz#1%d~~A!Fh&Xuh^NjEgN=)99Afs(*ei%G-?H%CxA-_8@$yD?Y1!&E>LrWtfS+H z_v|3=Xwlr5=!=Cw+W|j0)x&1ZS+a61I}uWNW7V4VT0*I=0e}e$+JN|7M_wu+SvU8sdJ=t03;W+#Dlj8CM{!lBq$}BD zn0FG=XZaEO9j~V=-PyDMpx4K}KYQUyEDW2sZrZkUmj>rF!iK1hNZ_+Uy?8~b^mKx- zBLahs6gFXqI0AjBr}@oUbm?&*Mz023A$b+SP5;pO%l3bl$i!vy=x?dbfw(k=NiqG& z3AX&*y&Xdb>nl+NiIy!QRAkAjjU3UAZFm~5aS@zV`W~Y$hBjqJ3F0>etU_R{ z&7p57ERsEFOabO82ey`vgul|4|JB0eO4Ihif9YTdQ&ro<7REMYdekJy+!

#jI9xif1vN1|k^=ws<2`G>IeMUI*$81pQKustmhe#GMo8ts+L2jv1pI zp(!yw+sS}m=2qYlcH+hBZ@Mhu>quWb#9&(T>HyXgOlkwodc@Vz4dLs<*eHLQ3%u|- zZ`~7*Jvx2LB!+2N9LA2HJmn8Jj)Z8JkuxJhmf9AExqZ>U-W43ccwiCA@Nf8V7F&n_ zzUr#0M`43DCl&T9(J(0Bb85m4V*DF*}LFCA)nB=oP#FFZDP@v@g! ztV95t{0b*93m_Q?y%njpJwaIhimbZv9?S1h(7&I3LMF<{UxKipsq)vQaEWLB@WW3& zJNVUcyuL?|9MP!DrePRMub(0LhWZzo`TqOxx3Yup*@-@^O0jm;ilr>SFqb(4PK#hl z#9RQpe%r3MG(oej;r9@C;4UeP|Cbeszy3y#af)wg4@m&cD*_lBG;vo+oO#66oA6}g z15OYY7H9^QLFcxu0@$-tqHlA3Wb<>7=MCn^Md{cl?D`eHP`G*Q*2|n#JPK3YYuApf7B>tzFpQQl;I1$8|jKp-{3g?{= zTWSZ-236_OE5%`US$ccp5bk?>d#U%H0dMU-#Lo5!IGntc02mZ1MD@Q)Q%n9d@mhPb zZJ|`Yljp&2+_nW^h+4a2xyFaA8M@dDO8o+lEN)f1>BA*|aI`O`{etENbC%dj! z`cgsdR!i-Y9U_J3EG^NQPkOoWL!v_!Mg{1r8C?ZU<+MgQ2Y{EYE>;gg%v0Z%I%P#t zI8~f)nijRurs(JVXoFF`J)i8=##BOT-q0&=9sT$VYc_1s3XKt&v_5aVMJKfz`XUwZ z6ygj<`tHLHhuB330AZBx>zN{4fmnN3#xVBhtt`giRF`$@)~r}Y4A#Qu$yqXY&MdN& z`1@dpruI$v(=DT}xB|O;<8SU>+i(ZHE4e48iAI3NS&RrBK0*ew+#nntsQ?}(fLUg! z_}jaUxo-DG8KimUUUF9e+>p!}mT}y~bO-id+%&fo?xKAH;x_Nia*>x4hBb`YM`sUq z%BDRcTc;J%(ETA8#?*9P#qUstU%1FZ)ci{Re56BTU`+?r{o0Hblnq5-?bVKw$oX-u zaoxz@(@gjbcPZJn4l-R-H{U4x#BT~`mOkn9GtR!~s@wlG>9IMBm#hXryql1k}slt161=_p=UoKdlZvk-}&HgpB^9! zH26Jq_=|%FSSyM5p?x78IW7(|O?ZF2zkehA3SzzU?ps(*bdzp%{u5~_)~#j+(gG4O zVu2>|1CQD>&n|pv#rkc#-+KQO4*hlK${h&Ze$T+{x90u$n$5|YhLq1V{ObM1C;iPg ztVrw-fh;0yzjQe#oxq3p|NRrzVqocNqq4VS@PWDB4bzh_ED^)oUrAy~XTHDl-uv&6 zpX5D~uV!6NLLV{}fa)LH&z_xpe)ARDEM{lL4Pny!6!drA8!ZXsD5GJ2Q(?x(2{=EY@0l#$Y#9{fohXidbArr z->S;}$lKMij=zDrRhSkPLdC<|)4)aGqOdBs6mTe9SR2^6rF~k<(=7Y7wcLTa`tD?? z^*&7X?*%>-p8NB+55IK>>SA-@9e(XBdtF|yi*QW9*?EFC$l@>0Xr1GwX=@O3@HnVhkEfV4NwCsg?)MoYto4imV+V`yV<^#xH$tM+)o3mlIj0Zy=Y$m9Pz7mcg4IhPEn=sh?I%uq8w`s^z?_c zKtK6ZjL+O_3cmmt=B_{f*hAB&j{D=CH(mvP`}o`Ni!n8`QN(ZNgfb-w?b{MQtES>H zt`+V2YDFqb1X*h_F3jW0R1oTZ4bqgntxEOrw_2o)GK~?`H~{SUo1<_fKGv(39yPUa z$k5BL`_1I17O&bE0Gp0-FL5)knp7_nRnkq@@@vcs*7=1onnD6YQWJn-?TozDNKy=& zky*jm-Zg?Zn3v0--(lZON2F@_p~vMHGy&AcI8!=&Kbkzl`@6{w^T<)#DFO9sB2B-F{<} zzf?L+uU4dvC?d#bRR-|4_rv>sOYxWH-gOj>!J%-6VrplxF0hNeS^(E)HT_boK&=)v z=qCwb!V|W{9aH-(-ydbQWOy`o(rjM#o(*4lhI42HmX(!`pbTzrJ zs-OC(yD{DE;vN)#qk%;)NAyqQuU$gFQfJV&^{jw!`y+}uYw-(z2mJ*8{`x-oI~Dz# zsXA=4s^4r%jG+M7DM=MVTp6*NNwuSAvmRGOv=Le|rsJ=`DX5}InsM3ZBHYiE_|fto6Cg=7Cq$P_pZC{&Lkw4 zV!#Dl3K+wKy#|F`BCaH1;fyiR7h}j&!+{Q0 zU4X!@5i4xqU|+RJ6}54;7{tPg12o2+GB_hP>y@9O{=gm*=~&V#i@$=w>et4?zB`Pn zz4>T;-U@imc^A`PPkv?zZeVP1`g_&07?guwe8O+U&x_*SO=L9FeO;R2t#{sen{XCb z{pOqM96q-P*BY~#@TIXB!KD`#{d~sh#KzD)d9O({RZTsSU0Da1^%MF1 z`OtZ_(35A?&M0l05tRIGzn#7&=MBdYqWziS0ZN)1K$flOUwXv<_zw^~peyRS=ki0h zm)J=kmLB!A)6YEr%3FSO?*mUg_rkK3t5&UpzW@+OY+;c+n1eSK6ZDRqdKR#?zW?3_ z=wBx7e)JJ*0FinE1ngL+91@N8rQQwyG)Icx5M7nZNt^y-@m;A8(b z6J_b#Z@)R|RNtNpxa`jf%gX#C@vGz|4F^hHGkIdPkFXe$si{AFhau!H93`mNO%#K} z&De~A9)=Q`Mm`y09U0SgK!UF;xN%e8>zq8PZhjRZ?%5b#f(UhXg;v z-xrL&a#@l|WB%~pKf7+^Fqa;zrGEurU-5_S_=_F74XwWaxA#+$l=|wHQtZjL9*UwW zZ6_^2p>46Rh~IuC>L&X4 ztTW*6b-x)qb=t8Ux3-|ypk8vGWY)xTs8Gb+4BDCPJi@`@S2_mHueH3OUk zOuVj1I3%$7yJnio%g{{%iZD1#n>_Z9cV3@G7X+^GwKR`jvLY6C8-J0)$lsBpMqPE4 zOAZ1Mtfz^>O6{aFw3L#BAk_3 zqeiH_i6`vseYnC*0ZlL#vpSeQY_cQMP;TF*3wV{8D4F^A{6dmw&ogkJ`C1R&KXJ?- ze{s{OW_^acJqBa3=P@G~ha|0-153X-Rs59MAGtn~BJh`1(i}f-mR=Nh`efH<-pX}I(uBx~y6ga_Gm)LD8TId6s{z!B8_hEQ+ zu04^qIO3}4p0fOc_dgfH7$>H!W`G`?c}ZtsljaktGtNKCFUGm?rhfd5DCq&%XsdLN z>5Bfd)C+yJ8YbOoMg?b{clq_d95a39yhTfwuUfNm?WWBeK=6+3SfF>H*n|Z?FX47^ zERgy5LlR98GsT=6=OKN5@QcIyU5e) zJw%#|&p!YB;{-pyO{nl&HA3P^43%{W;IARjteH)hWn+5M7_1kUui3I^-(UZJ z_~F#IL|w2@ZCJ^QrY$7A&Hx6S$cHHoPS!7?m6@z2os7?x<(V%X2BMtG** zd_Ce7)e3(%qRclsX?KH0dhU(0@fc>t#sh*e{Jce)uy>fd-x4rp`swL?AqE7=5N*UcDEcyP`niC{IU8dbp>g{!3P zR|>|(X5UaoVn4&PP&x|Oc}t35uvfSi(T%`daO5pl9?|U`0RGXu)2AiYYVu?(<5L@e zL2w(TNZm1lmfMo-R|Q}M@LhkoXN(r;N#<-~K?sc!Gug}7(vd-rc|C6rMGhlauM z82m>2hAB{^kH2|%>1D1Lf7R7jUwu{hiw)Ww66(FGs#Q$`$~Hix@z}r1l(=0`z@fE_ zwsNVN2*0vbwW>&qp`~#Q6fYm`hOVi6MdMZ}wT?=5zmys{G*-4n}8{`ebA8a~>UArz*#cH&ekSwVk>wGsZl^x_K( zpI=B1G;fYUUG-nJYSr{1-e|Y9V?R9lZK?C`Bwr{UijK`u)Xu9 z*A3*fWxkTX2Wa1}?D+F>gYz}zlDeDQp0zeA_{3Nl_zRh3HF>i$(%yT}{nud^RKLM5 zg|lUGXZ=P9u#hS1Q$+h+RU8gDV)B_6&0jzVU?NaH^PHG@MYD5>UjdBH!^H6xKP{tP z+1(YNsg0lM=S(2zZQHkR-?<(8v$3pjrD9YLtgst5f4L3)OD7}3T+!9n!5VgaqyGJR z=Z>#&e}=ypcpbA~9oAb$S3&_}NO5S~SBMQ|Y&6;=mMwYke)&tw&h2;Hr4#h>=U#tr zJwp-x@b9|-m-_wnpFb6BMX;&)O&fgD@K^OmCt#ezzTUoVJ9h2pVWU)=`7K=OdV2w{ zrjp2w5x*uvR>@%&VK5KBosoFRbuJ_kO@sh&Rw{VtaX_TfscSczrKYNjS^6HmfcDk( z3fr^BX9gd{1@WN=)B1bmg)`1Pnb?yDXXphhaze1HH;IyF42}x+x9$@QUGgz-eL*M( z5tAKPeZpI6&$DZowN#LLfmKQi&rTYmZ+8wqq$@1!Z^AKZYRDCz4Zsq)1nZ?;Gq7L!EvudDrlD&yQfstkwrtbV)RuoYCShnmhY~3ueulJ%>hM z`XF&0V_x3MUH2YS1xPL6hU>1rbmp1IPdGw@sY&`q1Jmv+Mwr+DoTUCWp`sWsK0R3J zz&ef|E%D!lzx(;)=fUtHm#v+FhNs_$znPyk^k|%Q8+4mC7K9srawEwnkhMN>9;zju zw4Uuej6Hl3a{e4e7ON?NgW?m&i682_FX#!JXuOnnIT`jEgV}V`+ zgei##m4&|w9;5H^-P`ejeuI*hP=_yIg#*A(JoX5~kJ|{mm?5O@x$E{Dubz9x}mwow9G`=fr^?|0_7~WU#JX^?UN+u6z zEvVgV%O(&kQzL)@E#GuMM1I1E+x&k1K>RGN-xB2*`S%CWl^Xp!3j1>k9m<~+MV5$7 z`Zn>cAv|l^7cf|5ZqEL^|Dlu5m~+kTiynD$#Z&43t6^2@LSX1ChhIaqX=bJSHr-wQ zhXT&%1MoLSW}UAX$w>avONrh%TTs2*SWApa10*AYci2x!{_?Q{v$SLF*2oL=NLxqi zgzXZAx_XV0l&3&<5q@3YI62>#c#h-(Tmjm z5icz9Tl{6_C(ujc3nl>go3Fn!Fo+If44oK7OjMDtG8WR>_tvaNvG(xAXW1l(u|vPi z3xK5c1)!z(11g$pBYmZDtj~t6#Ii1Y6~N8H&U619*|&F!Nu-%`^vSs+yMv|d2_U@pnLG1D?=M!BpEe{{qN z=U>tDw_|U`t!See6n}+pB@s+-;CT5q0?!+gyuh*y#J~oJJj8EnHpw(QNb3S?JDAT_cHXab z`OOoUXVMMxK(c8b%l!{J?3k0!yX?lh7C*wcv9CbdwNBmU)Gw+}XI1E!9_#U-u$8Flm5E9gS zO72jKB5&s2@)x@=C53p7;n^><0WWbYl~Sx}d%#AlFT2^|_;r}N)hW~DFRjnH+uUgo zEQHe-tODkX?mO^o_>WdqaEJUbG%%;GFv^B}+Zj|2SjLGy*;o6AN?r;bid^zZMk&4d z#^R`bFh{H4o&?}H6bI<5Z+l=F{eS6y^ukMoz=FWS_hq^O1H)JG8>;T!IvSzwGW;Ha zpz(mFBkzvwJAv(1n}s(L4vIcF$m304pn9P%2xE{w1Tap}Iu_Gc>03Op=&uBTH)Y5I z`s?r?-#pq$@efuTzQhoS&pvIZaL3}KAK$IiYB4O`yLibH&%L?!(=WgN;XlBy#Qg~i zw4eO3M|N`7-bax4haY}a2=Br$t`GFr6@^k8w1Fud4GD*Cx&dPt*HNEJfga1KUq2g! zsW0HCMu#K`jD-Nn`@Zb8sRbM>ebL7lpo3rPq#~F$7i`a1pECljEV_331h1t@t>U)$dt=wHNI>@>mc+>1GDAyY*k=!< z7@mu*;q3gbmG^486lwW}!ln?|VH&A#%yTUgn2G>30g=pIDDiGK!{3W9oFjc_&Q$;6 zgmnphkgg@q2w=?Lh5<32G`X68_2qNUojz@RY|rX9yC74@?iYDL`_mInruHC?B{LsfTMm$i1{^!m@0USY@M5SQ3%nwhs2^k!4zN&I$R? z-K*jWLl!yCQ=uKXPbsxDOqW#m(yCUaR<{#XS*tl4TL}8_x9I@OpOlA9@E~){YL%TO zl%o-nZLIC14xV_*1y|pC@3IvuSFCabq?a*|V$pb2L$v*YUQ!6Z&ft>_!howUp1$ih z5TD}nEySAKW+3P7J3;N1&p(5|8yOSm(@$v`-U6GqZr-xxv(K0S;;moO38~W82;m(& z2=hps)g{%Ja+uyc+tyWtrvOF_+9JQt))!;y-EJ$`N-1nBwzS7o1226Hfeq85xJJKLWGt+ zmbn5rpj9gdz}e4pVjk&;B(Z{t7-}Xi^9>1)e6_cn2xq9sb7er7uZNlWqcm z1{-M#d48{WQND4!#?FkPIp^byQlG>y$;pRoZeS)1gvjNhsavGZ;Oxa0p?_yxaQ=+* z0r0FjctH;=(C{~PgtRDManbo_o;c~Kj5BB9833cWqy+rMt}KBWFSe4VXW*e1?f9d? zufEU5a{t8 z-J}?!IR9(b7fm9Br?^kt zDd?LU)N1e|FL36Y5V*=D3LVOVlx*&zCdH*{e+6oqk!eEq4Ocm1ZpaZSR`{1Y&+nxE z^{Ei5EiuyoTt9a!3vfN({~)SuW71meZzq4P7$}hJ0cBLoTe+52fRWV{ zT$v=-6qtV=HD>%tGv?iV-?Aq#KR^4t`cvrI4oh?tTR4-fTLIt?=t#y$&kTNxU0K)W zZ8$*hq_^xAyp=Y7_Bm#04AThSty{53Z^9-`XW=adg;xJ!-lZon2Iy~SGX8Qip(g|1 zhF{zVUMKd|3omn89GrB)VibmZu|M0JAJfupcPzaBkyWp~|LGSy|91!IxLl!sZR;)n z=Y*duDGZo@#sNAa7#WPm)lSBeU@S!H?v)o)&F@YgfBB=qxOO9Z{(i@N2K=$M^ECH;gl@zU4bYw}HSPT}E;xvWBM2Yj1^ldwtW%P4Ykfdm%7Rc)y28nfqJb`deurx3#xtFxsnNzW@Rs2~FRCRUP4jnoJ%I*!zR*ANop z4P^*>VGZm zjd$LCy@DF9wpWKEFuX{#->06U8SKf&aKBo7_Z>G}G4qTQr%pO%JVCGOws;4UU@NBR z*y?R%HT<*9ze%}{Sd$xn=?H`yxftdqX80uhsH}`b$hwnuMG7)`|I;}up!BuGp(+>a zK`9Hk4S%r$<6ZQRudVPiFTXF9 z9RXZ#d`=lFgl!1z`uJ_~5aHXUHprO*=uv-8$DR5G}l0%EsJ)$7ks4qD!v8gru zcSJiQYn*%8&G#&YzrcjGt*lYp@nXxs1ULq-edx()O|`r<1FJ5v5` z!&PZB!6YH?=UAIJ8=C{mGsE&Bi9g?ho%&1rDbWR30MpF}6w|?W6TvzhD4M=HaTdl@ z3x5p^g$euxti8_|1k2vwH~A{xKnDZHDSqm;4?o+w^N0T|1m(|!iq2Srt^K!?!ZAVH z0=$b(z%~F|FJK%+%;`J7u@4f7SXfjOwr<|Y=!m$6(NE5rqOl^8zJ|(vb`{UN4pdm} z>5e3VVXHxD>~OT^9c@45b48W2&FBJciVL(d`l*#G;IHZz=ZA+D-ACWwYZ&?HG($hr zTh7i$QGY&aNgY>&ZjpB|?Vo|)o5`=wk8aA5@{BlXOZ9N`gb(AFQYBloz4-9he)QA} z{pz4>nu4Z#zAcHOfm5(ZVABwVYem(GnOFV-U{lpcEoxfD*Nl);GeYXGu+K)nCNs6w zV9K6eYM;E=q!f=s7%nZ`3fUBQ?FHQZLjW6mZZC!(oOR`O9e>OGsTs62M3xR#`QD); z;ShckBr1+aQZ`8%lIkN=>Afv%Uzd5FSc};lgp-yY0_uDgocC{44wx zf3*ph1m=U(Owl!8#^+isn$f+yqKM$QOxt7}L0oQC#owF(3QKwu=eiOJ>>Qz=;bk;% zoUq_<83oEQjD3o~Y18%+E=BBLI2Qpt69o)_FSuaNMW|zkA~Z7<w`wM98lN;LSR2zSZnlZSJdzxAy6 z>?ZMe`BtgFNEY%DS)nvbRher~zBXL)7rpJ!JiZBe8pW^NEk+~*&g+Cb`j8`!IeF&1 z8}EGJk(E#DnPP~6mtJ`JHADUwJ&8mC^xDg>zWL^B2nC}F(eX%4L069F5CH_BeAEcg z3;urj%rj4zbWB24rCOpz9{V#HYTR`hD?#|1_RscWkQc_Jr|vN35JfZQ=OY!rM~Po5 zG5iSNiUwD^-1fFz?*^5K&LZvIip=fr7GHaVGy`&%W5k!hWpMCqra&mQ8S9(v@8rk2 z3c%%t?VaB%w@w!OLsadXc+zaE&zN_6%t3>igsV};wgXrmNU zUo6qump&<6$rooaaUljA^Z~KxVzWpEW|b=rT|9c+3FlmT^W96AKeg&vnqH|D87CtB zU9pnJ2P;0%STtx*0KoVdeS`&?5YYGx<4E<@)-SeflDvpuI7}EU2>b;R937DlO}uFf zv7+&MW}x8jzej5FA8Fa~7w>1>y4Dkd5-%kvXN~M-M&_V-_32g1A9?8hg~m>&wvB(s zEeq~jy7JWzHh%TpKmYgkU$SawvsZ=-r)Fm+G+ z*>UTDuCGDySAQ-QK5-|T{C(_Ey#F7(|Lz4hUw6ga8E2j}HLbrGH$vb1cEMyvl!9*k zqT+Dy0Q677@6Nbg@z-a!hf-!9fm_jWLyTv?b3k6fVlQ;yNdaCKH!+M6oQ)$?f4tf8}4=!S**C_ zgGuV~I8(R+bc#R<#pB9vnQk6GUQ)y;sp)xfP+nPT`- zB=8&o9QF^${k-CmIp>|G3kCkpJ$!lEoY(w}0EWLrmcTZu3EC71jOTMw z;zl@bkDA$IM2!}3TX9}IrF6AauQx{l+&?Xa>QF!&2v3D<>ZCk72(?zt%sb*55;?Sj zfOR+hoqQKSNRo`1mQOoO{_#43_@b6U&!Vny-3>LMd^AkOgQ1 zT|aeIfxxfP%18qvZE7^8Sq3eCjOzb`_uevZ=4n$WP15NM*Ja~wqmqZ4_2o2lw-4N^fs&Y|q?8Uv6VN;?7*R)An(gNDo_z2yTVk+lOS{@M(ocNhG{Av#qu{I3eFluDL?J$fky_s9=V?maPEb;T#eQkv`b z{>!L?#vXU}#ecv1;pMAV(fe1kGlG}ullJG}*X8D8WQ#sM$Qa!Dlh0`3#lg9PJ_od$ zzaVYd0)Dq(gtj%90dYV1^s_BreuW40&Ye5OF962b80V&K#VmxeAh zxCN&LPq-+_-v{o3zc*;=!n@-3`<6ZR@|sV!e&gVV|2`pc6n6 zEY;K9%)0gZ_&g_Bsr)T}OZW1f$pXj3%bC|_cmCGJ4sz1#-{EU?BeT{v&YfbOtEfxs zD;d8BU|yLjS@Y6XCTg0u)7kztW$4d6_8oib?5nPW3s=$y^%fgTl5W-)NY_D=S{Uuy z+J9{jRt@`Y3&x?Nkqj){^n{d=BFb-MQ7Hf9w??_Os37xC45jZ#D61pGhfki_9#s>@jre_ndzkDuUSM)j3Y)mmK zclG@7;e)`@zgnQdFH)`NZ-|j@Gx%KT^?XF)Ua<=$Ed{Ypq;Z;TPxL7WTyC$yt}G8NoA`rhy**4h ziFU|OB58ehb9>B}3xEDI2lE&y1pJ|BE-sg8E{}1H{B>&=e~}EX(th^JnOd2w+Zl@H zWv*HNGCztk+H6#56II(k3w!UG$AJtH!(aY(puspx;StB!XbPe#;64F7Q#?&W?+R+ zKcTDer~Ki8WuT62+jo9Lc;)ZDL;ilF1N7ES1Wd;AOvJ|Z>puKoEv>AuiqpUFJhisi zp^1UD)N!G2lE3(Z{Qb6jmn?tbt@U4g{h!#M5xS0XMEa31SfrnSDjDn-x<&s&6Y$SQ zf`-5G!20@YVpG%n``z~d8M8F@aw`g3J}0c#nm6?gqtj5(tH}oSyMjS01SqcKdS#XS zTI|q~x}|sN3Ghn7wc0)mf4NF+`l({r^L_d9@V7;toPRlypHG}J;mAYq39$9IJ#0b8 z;Bm_@+2O@swf|}5PNiYycI&#&?3%-g)+U8>E(t|y^Pb(5C%xNwB+onWRc`9>E)mT8 zV||q8+(L)Hfd)=l7!;TBImL{vLk+*f{7sG6S10w5!9$$vH2(V0S2Ajo&d?L?nt%RC zbv>DKjlS1ORg9)sZL`kv+WG=_$&!ZoDsU_`{vv)@mV!QX6>LfvO6;W9?+ zkp+2MFC>+*&O#ZLaEQMO-OhPAOcY$fu%FEoTdlm86-;F)NJSL}QjxwF5*--=D}M{d z^4IS#_1LwCJJr0BvH&a!`=m{{<8LE!Coy|6*Y^>@Hzw(W6?L2@;_QaLHz9e8yfuZt zx?APauhIxDf9r6Wwdpq(E`Yr$ji8ZgmR#^;K^I6=%I(7#L1I};q;h{6Dck$`mj9P`JFtp7_ZOk zuek8M=~E|7oHS|Dxsi8}5&)H*U?|r@&XNa%&FkGv%Ej2YJKeQq1=5+2U6E zLufzHJ<7WefJe91<5-Hh3co}V|HU{Q-3`qRHb63fzSWBeL?O`m>DiZ6>&izl- zXfI=qCHbRyOyG+gW&5gzWUf<)V#rRzWJ1c`}H8THIzo`Q3d(e?n&$>wdK7-Bo zrPp8AgU(?Fu%;3ZBc#9~3t1;kn4;v~X576`#O;?~GE4y~*FS=8Y{n}K`AefOJ(1Qs zI=$c60m%-)`ZevUK?uL5|Irtpu?fw;xIpuN-C6>Z(*GBuhzgi!7c^r$z4D2Nok zIMClSUNLKt#dJgZa?_{liGxK)_ZM+l)>)9risdUX+bqZa{1nC>H8GA^8hmI6rYk_A zyD^EqN3X=!Tp*BkdInJcq;D5`+UOg!{?hmNk!26vch?;^&%a{s`F}li+A(7f8*|`( z1Xl|GIzIZW1+=2BVA#*}Z2Zq>JW7L7p5I|K@f-zFo)Tv9F?`$s>@qh5`Z{7>kd#pk zU%MAQ7Ak26u2M)2t5Xj#f;X9wPw7FW5y1#v!=bqLskWz|})3 zhH3e0pk&mZ6pGRLiV(K22p|P-NyM6tBybPlc@4~Auo@WX&XvHVe1^n%a`z&`^Tn{ zzDVn0aqpXEwyYu)fHPwkq_hCT-#9^QfmXm@e({_cXT|HP=o3|tMAk!$s6puXC}lCs@;a>`tvld!NW{YxK8$duuH*tF=w z9|lV>;kzGVkTPFBAr@hi6$c|vB&DU1t?FRy2^{$m;$zO-7Z>D1F`|#3F!_YD=FFRa zv1suPfv)G^4S*ouvx%Mi2vdFyepBLCrC z`ZBRTajmp(sYLmzYz)AbJDXa~UNDm?aFlTWn%0bOE`L=dSSX~l;yYj3y=dI6O0pIM z^JXCuDPuwQ-xh6-TF6<+EaOTTN`#(7-A=66xf$B}2=No;R`WwydlSj2>-ZC)f2)nK z=-a4DhOM}V@bxQMZ`*56^J)2I(Ib92AHUa;$DTgt+B?y|5HF#x==~e>bGfruBQWp) zAFVBu(U8{SfrYCT!6;F=pAZ)sm*~$nVR+u;pn`Pl{dm2xo#F3ipQrz?y7K!UcA+%C z|330}v(Y!!k#NFd5Wf%Kd!INLhIx$oRfs>21J<$!@4u7bODLeI8sBj9g8Ls`^~$>& zFhKvW0XTl8+tDvS|MEXS@7lGi^sfN^Cmvb+V_ZV|C4t``fBgB^pB;se9!NN4Z{N0! z5r7FmNmj|Le$e0U{0iUh_4ESP3EF_oAa|vPXLRoh`|dvZB#ZW*Hfck!6+Ir&+{l+} z+=j+wZ=p>w2H1WTCo?^;jC~&0|N9o+dc#$h%sOZKag)Y3`RkLCI$Pr;i?!C6|OY-HZJhd#7k)E)FyqLYVdPJ6TpW0=5RbBFsMc`JL<|EWiF~u{f|CP{$8saQu^Oufh|L9HHx~>#f7-NqBEsk82L-u4Zs5!%A87_ z)mAet$>9hBBb4kAK3x^dGBYYgSQ}$B0G7sW@xmsHQIhImQ5LtR&K?~)<}{vaw^UeW zW#cor>^RKZY2>UMyayVkdl{RmMRrINHyF(cVLca712J)3%G?Cx;5gN@32>9rZVaj2 zys&$*ovgSzuEQ=!3SbS;voaI|7d-cZzny{eqOpc4L8Vxw6s2N7^QYEP#GHRM0V}#Z zkH_m-<7p`)^sv!=WSuAnGybx&Rd zzP9oymd&30EdaO7TU%8G+eSH@>VU4{J+Zt`i5_8g(3nHVPMJRA!ppC^f~N9|E}l34 zdKyP=y@gI;^Qj13VN=D0gwLK0c~6)!ar{v0_nS+kw=b8cGneh#UZvDSD1yScGnJL! zo7wKNH`xCa0O=I$3!3_}7*+-Q3MaWBf2{^}KSkZElp&7$SS6|DfLn^cHpC%y0Y$Ap zV7t9G_wLUXB={viTYglaEPwMXWZrATH_QfL(c0mcvci%gCV_Um0Jt?Iwv6&?@u2K? zz#)?ez;Wk8PdsBxV`u?8l)vdorv4@AGiOTUz5Q(7VT_}VpKbb#?!Llz!+OF}B6~Np zf;L|V;&WKR4MeKMD_Z?a_amBrX;;OhOFy6O3g-|91;?>uE&$?oYe^u?xYAIy2U68&*tm7&sfi*#IG7QJtt3@V~Rq`TvSFB)^CTo?; z`NIZni?F^}_#a|iu50jes7gR#UCC_;<|e9#jckGo77f63KEn0izP}4@yjJV;NmC{q zb(kY)@zB+?l^-|I2rLH-0xUfe|HVw?polW{cgANWLy6LA=-ml_b0?~nFgR1oMqu0WGvdpk zg?254-a1(K-ddOrl7%X%USlc`F64FMrSdZw*Tr(bx@br?`XpEAKh zAyQgLK@tQW0x%tt5}mR+X3@D_bFG|;nKcA1CEDS)7r@2C+6)|-I$*cm1eJ7#t){{- ztPOt46fKP_l}Q>NW|zT{a&|On6nC9-XzE%K9QE5s%o4-;>Luyb*2SxVqwC$?t)qa$ zQL~*&L=>*`TcmM~HKh4i&9zsZl0S8iRh>Da? zIhzk(OF5pFTR~+OAQ{{nV{7o)7hH7FjOkMmwv(qFf65tWo_YEyC!GjiCuw5#GRM+O zi0(J(@pRY`<0noz{-l#nK5^O*e}iD}7JQ~Z7AE?m7#u46#XY;drgd|ukRoF>GRWJy z3*L&%Cd2Z#@S8ZGrGRZE^=*n#fbF>!2`py4$G&qRau)XP21;TBK}NC)-BO@D;BRG* zSD1}UEK_`0zG10OZzbKq%ETdm>j$l$NCUK02)(wwE-sWSFpC+l5MxEYmBx zqSvd0utH+u$9CtsB(hn-MRDljqgO54o{HyPH@CjmH#osv)2E#V_hPtKYkiWJD ztBi?rh6~n)4GhCT)9=UYHhjDu3}b30!D5Wb84hRz%6Q}Fn>KG|G^Cw$`Yrz}47%G0 z42^&EC+itA7u)lCnt|7^H_Qb9HnJlGR(ropVDKlGJ$TQ8+iv;0Z}K(QTzAv$_bgrc z@|ty@Z~Oi~@xa3V9FeQ&{Y8gpAxr|wzy9(geUC)%E{xDWs((?y+ZZ)MLo`NcJ4<0O z--Tz^_OHHRECxbk+6HW|-N1IG?I)OY`2YChPXJ&vF`ij8tyEhJl9v`^+_G#>w_Tk& z4fP5uHzWv+_XB;LSFT+C_@j<{bkCi)TsP0IzsF6&`6>e+HPx42x4=>S6)OV}4ngK$ z%!;OtQQaoPJZ0X*Df*erc@m%3-63C0|3jr5ydA&gDu;@ZB?h6qL{&V8%q;38n`2{I#>y;&oIQPZZ{xwL`u`IEvBHT z0eG0eg-wx}y@Jw0b5G%bSjF3=QpSj4H86UT9>Pfj1UEgb^zIQ0KRY4Y6V)#RN(FF| z3OGskE6nN$_MX>eg07R5A2Skoo`fY0B(NH|Uii|?S6HV=rQ(uH;!vhZUHMD@qw`2J zv_Q|EGwb}bjoDvQ-U&*$PVSV7aFe~&)8Y|rU=q}x#Sno-1d zq^aLOQ!U1vM%MUkis)9MOs%pet^q<~vO9*QG9s9r$rJml5Y4c~yYA1?zm)xIVV3-B zve+>l+Oa%>ChK}}43@Pw&PoE9HC*taZzxkFm>|LbpK6PBQKHn??Qx@4Hwf;eMs{A^v4nDL6IFuC|l{U~K~YV%$vQXBaFSMz-Wk_wGdu+p$&^ z%l{I>?M0@Pa7}6=l`mdaSf0|OO1HGq=9G%=15;HqADp!9=C9+=W3A1*(=Nq3P8MSf zVa^}uAQimhv$q!AK()Ice&$fzh~h6fOT~gx#V!4E|AUV{>2LFHUG&7$1m7?bcT&uz z=dV%C^j3cb_`Z&M(=+;21B+sT{%9TJ9ewigM{7S?`|+o;l(bPMR9-d#%uX^&ar3}b- ztAT=el^Nmfu0@ZodiDL!wtYvV?(ZiZoc#-IfBm1Ip)8KiwN47t@C%fGu@BNu2BI|K zYlYPrUA}EQeUS8mhQGA_{^LiYQ+~6PI2@Zc5(rBGV}qvWQM|77or1rNobc%5Ps(2< za0XRKlq@cVUQ|pqs%Pr$ZL`qVfj8~`Yvi|w7TtU2t$)Azk_*np_nF97H2!wZSB0JM zqWBp0=27}BW}wjTt}HeU2-RTKZ{42E>^oq5TilJmwJ*~@{2>!D%*@bvi@#znCLt+C z;{C~!$y4X^-KAE31j1ES_Ia;&mv@I90iiEhZUh+}IuWzxCMRznLu*EE*e=nJApqyK zHJ9}k`?*_^$jO73P^qql*N46bdmeDinZ;j&QK)rIy$^7V(l!U*0)R;a0;__xKr<}@ ziyYfX0jaz(6^M5uaCBrg>NqRKy4~73b}s&AS;~^4A!|Oi>9XYt;7Zx)veMK!^*o|M z4)K@SssX@76)^vWZyB2lzdeK_e-*J|a0g+m=RNBq(mfkZ&f+&oGjtBv_Vb3+oxpP4 z>JMq(z7YTCSuH$Qgi9LWRaD4@A|BgG&M zq0{UR)p%(Q%)y(SH<~xq9Z7;atX5G}(P<}3-f3#kGCx1Dm$HvgY-h@k<1@rh>u>AH zUB~wP1Y{;RbTpM1s$RP3VAEFodKfm%?~@PaazD(4#YQHUBNm1pb-&SLk3Z+Kn;&@M z>F4lHN1=gO=qrRZHyb7e$Mx!z1e#xd8TTS0nGs&`qYdlUF|hMT^auVJM=ByyZrCVL z9nxqWik3K)n>KugQ`UC6{wDecijwgMQNLRl`v?zdOwS*|?N2}5zyJ*I(*BE65?=B4 zexm6V`S>g$IP}gll%1oOU4P^4_by%W;yW9@_~u^^0j#OHAj}7twE@`vzashPpRqox zf8j4&{y7+yzu(i;OZ+P=(8ScV7m@%*|Ngkk^*TX+x_+%D@>g`i62G+m3g5UiJW8KC z*RUERv`GvbF6%k`qWM$p+8a;9v`yR@&w+7Ap2CUiaq&y!jlW-e`5elSDHD!37~kiF z-ca-fJ58_+Q~S0OrMLLQ()* z?j-r>`GEFmu#|7Iku}mrUmkI8L^3Bq2f0cHM&{_>T$}qAej|mst-P+8;v~ToqVqvL) zA#j|OWanjK5C}R2P!WkuNe%-zNDY6pY4*&H%=uj-D=h8++(9fR=`0Lw)p0oV&8Y!x zW3Ipzyh+itJ$ohafWMld%YrPO4Sp37%*cXVAHg(Q>gxxXo>jl9`fl_E{kAw8_Y|u< zHfyiO{znn)>0DL*SLdsL5x}$N%$h;qh;ibVvfXl12A8a4N%lxE$6Ywg_|A#UWUDX9 zwoe8Ma2_R$HQLb@VtR&m^2sWq&!;mHs+?dn8-OPcan#{alWryt`K|yQJhEr>lMgiy zOx}QQl0rWG%`VxoSv3dzt&G=H0FxbGn*o14r=Cr$r-%3EE%EzDb&cyRxDR z436%_yE$mqf=snM|C!)U)uga5G_%sx{m6uRxmsv3&l#;!=O;!iB#{AsGk)D%3IMKi zl2H9+lv@_ul^@!Q5;xN5AnAMTHFz_vBymiCBo_TN$=m?`FAf9I%E5g` z9dN{yvo5;vzDJ*~&}HBkKcnJr+=c9h1cmh@62Iv`MpRKo7hs&*4;|kVhXdZQ4gedX>p2uKw8aGr{yxdjnU6j8 zI1RxhD2!t?e?c*h(iO2I5jrGrT7zXVR0h8l`igOm?_=DB>n@*j-dU#}KWW^dgq~}C zkAea0u0l8rjs-Rp86fCCnJXq0Dod&sM+f^h0Xu}Y!FRuzle!}gxtspwDOar9Cele@ zYn&$E$@cK^bheZSwB|GG#8;=`mxH7p!iDc{dG9L#jk}8Goj17Gz)EM00Cs?SMK^kG2Ij2GMOEVKD_qMN4npwlX}D z{$6dnd{6)<`B2v*?NgseIQtVu&gmx`a$x>@P>Xu| z$Tafr>-)lEsjAcbeCpYlpU*t@aGZ|w>10@CEC*tMhabp@Lqe;0V$_;TM7?LBk3Fb zcFxC~om&u8nm4n-kCNT|io577v#ugdbHB9rQ)A%kR+S(|S?Uk9r+Xog`2}0G%X{n| z-ek`}^7!o}In{oLO`1OE`h^ca^&-5p2QVTysdv13?Nx$E#AV3!FTUiUw{N}8FasaJ zUtzm;EinFg-8z)-+7CYvzyy_Czk%jp@%zGa zZ2w=o*b@3#{^B33t@b&(AT7Fkfx~E%=3jgLEejVt`SLp-Z~cxo-Hy1Twx4IlWmRrK zi=UN=t=$UcOM5SWwEyZ1whJq?%dtPh-yL*7+PU4J)>_Qzg|w@@pugE6fE|m0ktqm- z1zDd0z*wNMK0o%@qmKY!%+Qa;8A}TDC0qFMbX=wl?n%2a_gA-P;9Idb*!z)(8Rpnw zkLFz{ekW6h*Rm6%Nvy6t6f#pbXyK96L*_r2kwZyt%gl&fc3&RxWo_@iwYs3E@-?x# zrrp;A3wZ%9=H2)vSn6~sPce^Ry=Hk9GvPg`jRwZ&h+mK8)sM*8(7DatP#UpWx6t3T zcKh*?|~D~x&;107n?xgZ!FNL*|=XdGznn!Z)0vb zV1>RtfJ0y;aM$Zqlk628snozpJ)7mPDQuFmrFJg|zp}F>LFbnwzi)QvAh=&B|Em(g zQQVq@d;a$17r@$|dl4SPG>k;{BUia{P0ro|uRO0S6cwc&f3ZN%m^pLCUr(BNq^4liujQt?MU-VZW=}@l0PHq3hP@?$-(Z`KacKZx zZl?7LFEiV4BdZp~Dvo5^a9N}Bk$Q)dy1g|28nz>eZRsZLYaM46Yuxrd;*|b4VQPM; zun~yz4f}Boa+A7(NdYWFy^Ey%O3icY<5i&NR#Nt{uIIy7mA3RX%Pt{s%TxDI)U}Tq zGvVZ!*DhGP^7#ZuDfoiGS6(4<1PsPw7Xhqcny((zu#^*WCx=q+4_tA#b!-kB^Zot_s!KbFUw!dv^GP-su!PO z6yS&My@M!0H!z4d@A$2EFIoBeN1L{PuSvN}&{qI=e+A&8FyIxx;WI#{v(b+(6Pd%P zSAlQ%i#EsU3IZe103`>(g5**AQ|fP$~TA9qY2p5GbsXTvOjM?d z(mJZuMERPxvptT(AN3@=LAK2sCG<2tlj?|d^qRJeCldoj?%eQJ{ru1Yg5Eaqtt5Gh zmP!J%j^Drxm@GNFPwVU2pZ~Pi=*efpUyZApT?K6={GU4zrDM*G_WvjV6NjUGu$l&r z04@!T5xN|qJA#I$P?XPM0y8fo!?L1SO$)!S@4tp#l9%r_No&HDV6o&z3j1YNql1UA zUEmhrYE!xE`7>>LHkwwZDtD=PBup$bdVZ(gA(xp6fu;4;u|OAp%}&w&G8%wkY|b*o z_na`7STzXwOTI6%D-{;#xpSj`@xZbLc*c2WPoK&#gK@kHIUAOmY^Bi=^rj;#$R)Uj z{f?A&^4E^8e1}(1k{nEu!yWfHKzVIxh(!d--D4(BntbfBlO|5YSbM~w2g~0My*+t@ zrh4Fcm>VB_kYehT041|>DoSoj`XHQqi+nINA{S%Ez_O0JHW5?1t{C2&`hweN8og<=jK`s5~k49A2xiI#JM0Evs1I9+LP<6JZAI^ele?o z+~ulUMGd=C?dXT)T=I({{J^7**8%Iv=WL#Q`4yTfaTan+ANr|Qz|dEnjro}k^yI}W z>y5YG``}%y(3McY?}J|czyH2tG<-;pB)p?HeX$wms~tPP|NdM09ch2wf$KB+m$8CB zmcQ#i{*>;*8$Vh1!3PfW=O_mdSRW;5Pt)^rctG0#e2aa6?E!qp{f|BW_WI4+zy0Bt z|5x~J+Bbx4+BfJe{{Et|`Jc^L&8nXhg5!UFMFPX$T{Hrl2n&+9nBVN&v12=F+cs>_ zJ9gM*3OXA!gp8AGx=F9>~2j=N!mcnCBETmAKL`P~^oR5Ti( zDy_GXuF$O6F9H7*>T3Agt52x_{+gl z&bf4mzv8Dya1(;!2|lF(I3{T6Tk$7DWbMzU*r2;H2^$Q>uEdh3;a_@&(}5K-{d*IVqyF($$)vA?)=8XIJp& z!lf_xMfe82k-$;F(aYMCO;=p*flUVcy28v0V87JDEv(swi&p$r4I%KoXs9Q10#MQe zNdlj9`f)AZq@WQvyNZB80BrTHafu=xDL0jzg>8T`tE$PEwPAGLKwxuG1iP9hO z#Y$=bqPcyvZHk(bOp#U!xcKYaBTYvicJ#FAXV19c{4=MGJJ{x59lg-h8laiO*sZMV zP(n8LKj`2?j~MHv9mB<0rJ#;tXiokLztuN-0@V&}(+3-eQG|7u>LCu%afQUXdY$uS zwo&BzKEp-7lAu&7H^&Wfdz29L|&b*ig;AiZB^wLX&f7DwD z1#G}>$C7-5v6^8a9ct2i87HmyV7m@h*F6U_=G42+#B zh@V_;-=qY6d&VgiX7sk?y!D2wFPnYNX(u`Apbs4e84CXZpp;qZzbG_y z8sHePH!8FE(xAjb!=^{^+u{U+g%75`%A5B@+5=&wk%bShcA0XUWON{0l4Zj z+Ci5UzC2*>eyfj+Zsj1A)tWE-S z?%&X_T+Rw}p$3kGO;c`7LR8Jq5xrjYO*eHd-?2R_eK97-0$nrZX$5Dmu(5f>N!w}5 z<(hpoRFiv1tzM7tEzwRqiHjToc=nvRvl)c&yuY1$?zvc>Gtv?4rQ8$1l7syoC}DBDpXbZ2EU@w#JZj?cr=9(`8Rwoh(oL4^v(Nsc4>^o0)%|-s zkTn2hTErd0NcG#{SK&YYNFyd=?KjB}kFl3&t( z*NGn*0;_`U-sMJ>pPbhTjo8*6Xqw)0uYC@lIDOXqg-cgFN4Hzz5)8{v?cj?9pY*9)1`JykyCerOO_9a0^aZS=jB+)U zv=XQ==Bt-vLFMb|+b~#D_n}^$9Ht$#o$q%)>hk@n&%wW#=`vQenSRNwliOyIZq)`V z0+n@MQ*vsJoY!c-!;kyhW!KKf{W&JrC|&s5617HFLtiIqU=S5Itj^?I!dE*qy^xGq znXbSiP0*d?IW45BL!G1tE9Gz$GN2961X&2|H)W<~u`tXAVQLeVZ9cozWI$h~DfneY zFM6w=&&ITfNRaK;qXY z+((_F-f~>utAZ=QNz&DbTn_-AL5z@bdTU#$0Y(bmgjPN4t+sy60xzkTCMGBZ=-N{ z4F`@n{D?#CILU%&la@IL)1uM~BWx?8?hTF*!8S#JL)^mMDya4=59 zk;ATtRvp5l#1buRih+rq${*}X3|M0TnT-H4O=<3F=7Y*D@)>a2{@l`XhW|m>I_S)wlh9JD0 z9>C8$PY)zRH90iv#V*fEc71Lc`8UtKWX-y*2N^UwRQkNkcpPDPBRQL;ogWf9}oCGTNw<#C&Fp z9~};Y^p78Z{DHnldOv^3P!Y&q#sN+Y4)Xmy0LD=ZeQYG?jf5Ln%V>lN#E}-@70Zdf z@p$adOP4%E3V}f}>0zwWOO`%dqSzoExJ<8FWt^;)D~!ZS+>M78-M8@eo35L8p<$mV z#`g-drr6;{Z3yNW&2!3BB9u&%7Qcs;!cM^C*9}8iF0KZVHCt;7noddR*|x2lfY&VZ zMUd-P-Mm}7dD37X=626kz{W}e+@(?hzC$hL1>l8pG5oEUg4d;n&_ZfBIQ76m@e{BVowY2(@O7TMB zW`gFMAXpK6OX~~VY|k#HTT%g-U6hUb9huawYT(FT_yxnX;fh~Wq{(j>OE=p}v!Z1O z;O^7I1*Nq~peN2qoe=d@O5b^&IV>;!c89E1V9sACmBGQUhGzABY8Q62Dgt}OSfNP) zu$!CHR0OOa^d8!rg`}}L*JDl*!CoYrM39r)O9J2)*1Ei}7=U4xAt=u~=d4qwP3U|6 z%HAZ!ZzTb26R>@TL@voWwMzKw7o{?@5!PmXvjQLO&A9#Y(M!OI!1tI5N9&2if9A%I zMSCOGQWW0XY%23aDlv**y~x|?_#I-isEQQ7m`QMRdqR43e0TMs zFAv3^$P@Kc{KwMV0~_JnO}K@5EQyWzqxUnKtIK_A_Gb;z{1?4;`~4?fd%s2CqJe+>;ai3u+_A&ZAP8V`sRy*aSmd42 z2=SE00u7T51&tFl*Zle`FJ$;Y4aqn@V@4*)-z9wT-?VhegAY3Y&_hd?VV9;k7!^#I z4wNwbrR5hoFTVe-+isjc?;?D!PSEw)p1)M_d~1j6%sxY=;(?^Vp%0NZ%-~R_NaM6E zb}LwH&>avf>w2)}`;KE-TYT-;7wg>O_fk6;AHQK+mrp;-4#cGlilkOViM141A~<)z zi|(&@_^9n%m5q`4Ynx?@ns;`1=fV8H{H8M8^4b`jkDkAD9--9a=0ucjr&);hGbuj`M0B6{SM1NBL!Nb5$G)4FdF;c)Qchg?ViZH7P z8;CZNb=GHiS|G0vkBR;H;+6`)qPOjce>?=*HH`kuPob>!QuJeGx4 z-g%-zo9C2{DpNc1%3l@%aM*_y_jfP?C;$$;(vyje+^iXjO9HzywPB7MXx5RXZ?~=F>}zu$hn{j2TU zzSz2T%NFok;`d{`w4m_E7!C zwC&rUn(vkTrGF7H#k2WG+^K$ozXF)KU;keKY?E(u)WR^$D)lc3+cT;btcqYP&Ghl5 z(RbTdUxDDQTM5E}+t@dFKL6wU?}$PPq`$)gMs$mu(VkF z(2|E9d=M23b|35$1b&nxflcW$jQU;j;G%mM+%$h4uFt13>cSBWI#~XFJQeac5O$j1 zs_Jn(ONB8w!pwjsnfncDToD-kW&*w1x_-_Xp~iaH%S;5Y>tblG&0VOk+;rr^h?DG= zwQfG|9#5||soUMlalXq;GSN?1JJ_&oHgd&a$s-JwhUPqShV;MX^eD7&Z6y8N1Jueye=zerc@%|fR^snAq(D)@q@))6VAAF)s-=x%xoR%rc) z=hFyW5>Y5#UfxMXB@q~w)r3z3}oYGp9wF93VN;1)kD?awhp#|q75#QfayXQm>1%jZh|Rw5&pFnm#e_++1q zT1~(PPQ!Kaw+*{+!K|5x-ZM@=^X$K!bJppn7SU#ZRvBG|?a|T~Z=_=?D0DT0vNq_AJft-_Bg~igl>k)Orch52o07eX z+C1Druf*w7i0RM-mFMKv-1pSvdP3jgZ*Z(m25uJYVlMnuj&XkV^Z^8$bO@x0$BZYI z4?aTC*YNj1@c{|lLkQ;}O~0illQwE{fc>`%cZCl2vd4|BXweCa9r})uk;-xJG)<&7 zmSY7t&_m}GW>Cz#1e?fgn8+lMM9%(23tw3SSf{y|M8ghQ8EteEYei%5acX-8V#?$) zAy|p=Mh2L2+r#J3RShXcZB;(?AIlkbC{l6o@HKsC#sQ-lrnDHAf^eWtINF|AYtD;Zx6; zd;MJxuXyH#H2yx1o318coShARMXRt@X~qNu&#xN1i7vpegWY%DeiQz#ehUjU@O^L1 z+dvf8=Z}dgNo?rP6MAy{j_u!kk8cw^tH$3gB<#2(bZ;dhcNkrHH4VVHK&SON3K;t{ zI&s;9_ujRTQQPjg>;9$7pL=s1osat9&%geh02<2PAAZ16yvu;i-vd`Xn|}hfyEXng z9CqhdI6eF}yWF~FEBC&L0aM+04m<`LqQ$B}M*voqOn-me;4A3&( z)Q%ovI`J$ytvly?7O#@Onv-p)4Pvjo);dSsgX?bq!`=)P@U<00qj1iyI9`#2tp{w` zpiTGUOLC1KGj)kN-R0QFx%g@UjsVWE3o{vMfiT5Wrk!y7)X5XZ60o(B2o6HxvZnDKBPi$^f6p|k=Y#dr-kah2q++6NjqmMmXy6oJ$)&XExCcF<`h9@cEexTl`NC-vSvoVtKnJhyCFqqW@q-p z`&er5XdYH=*R;seC#ciEN|E5iZWF7*+0ucfjwOZ-SCSXc{(5(NNOU7S7em_dm*XDfPfQsM!w9gu(ssyq+vk- z!#EAfsNcG~xr=2?kib@nC9BtxsR(X0A;t;j{~u{>?%!Q5)63q6qc|`FzYxEXg{_B0 zOz-Vcyp>Ae_Is4v#ZWPNG@ZzOaMI;Wj&ss>a+`pu?4$-5`s$=cZx(XM!F>e6V7zOU z{%zExz4jSB{)E3>e#?E2JoOwt(Dsp0|0;%U?A7U+re8usmTQ##b6<57q&MGw>#a9w zw0&!he$el{^A4Xx<-qmX$X5(U2*|$LhK!8wGyY3o;eE9g`Rf>k8#4L=w&%6$))T?w z!}nnMTUfh^Hr)tJ4zxc%Mtq9<;O`v^?z(@;6VI()`}y{N*q|GAOLS)p&Tto*3QfOL z%pzFr+55vTT%XGn-SjUw2EDt==UHIev$vA&&pS0gZ{2DGwfv>s`aAufiOoS9FeiY~ zwqI+4CR#NY{xW8Q=KydSpy8{^_d&6{*pCP9C*4PKdjA89AB4g9W+8)%)=M73_OjrV-{%@y%W!A_faahx1 zjD;fV5L9>5xNQrM)6m=V*Q1R{z^uzt_c`EOfz{`*OO{o`%d8)4?p&A8{?z^1%uc`H z%*W z-BfS+Uj@hNU;xZ8aWn#V5*SKp|Ak&j@lMk8+^0~hkxP9`lBK4G-^_RG*`Ir<-~{{_hWYoC6rxUFno1tXDco* z6$I$zK^sE?M&&5y5{gVT7JGKP)9lA3Bolh^qM%!f=NUJEKF+KUeL-|PrahK{wlLYbH26sK4ELf`OLfSM%ms8K2GBvRokUlxD!bA`YN>}pugt(B=H9iTfqG`o9% z0J!dC`x!W#H#kDZ!Zhv7!77i1^#L~UTYsn2tj&qGtsG@kGcDv%@?yPthBl#b8V@zA zVZd%moHvhjRW)>Ko}GB+iTXm_3k@wuK~dCzQ1-Yt-l*T+e8;5 zyq~vz1%4UOkCxQ0>DTj>blXhBF#M&1QX*gxxpM6XAH4tGJ8Ry4n-*XPS$c&t<$UVP zCkPO==$?glE?BVep2d%>di9-;zhL;^*1k&=D=>;eHGTK}cm5BARm1;uY(WySCpAGU zhkyB*aFn__U`_@ZbT*P8a<2hqF_Jb>(7^Z?ksmvoQm-uoViC|>fg@GVv^etgV$@0Z&OfGY!M3k)yETg0PY~jlaT4Mv;2pW}%k4X|US} zEad)A$JU109H0@nHp?1!^Q0bqI1M1k+QCAb%c_Rhpq5F4@o%=xitf-Y7wufNRNp!O zd#C#Su6aRBa;~Eo^I_P@SpXRRo_WfYaax^I*1_1Cfmgw86@b+l$@xzEVmgie z89OsNSJ*oEU^)3xpxW}Q$fdb6?Y$aZZR1t*!ZWa)bckaksRR2qSf|81~#!u4#!ps#!#76{IsZXm7`=zPz0MF1TvmWU#f`vgPC>s8zq7ib^uUS!# zKtC8SXYpG|U^cWwc|wZfFQ3IC79VcG}hZV7{u}R4vRLGXVAg{0ET1s*=+CiMAA) zCbtL&Qw?&Z-7AWHx!HVc%_Ck^NS*qnEMbezQoPCMc56qadV{9*Npk1~vUcE@!*EAC zMz_1M>Gd6PPj#YhUh>ZUwjNcSS5t}KdJI%k%(beSCEgx;{`tW1C!BNX-|t?!;@RgR z@6-0Jd6q!~Xo4kN1VWS+;iB(r_(J1=^$HO==mJcl{TBfH@13{bdiT8#K3Zo;jg6Z= z-?U{5eU0#B+Nl8EN!zLXjrI9620zmA>LbHOuV42O!8>rjdIxhheT{K}HVTKfZ(D#@ zEq`no0{HHQ3vR!C;r&aWe17!@pMLo@_GO)^e)(w^Y^3!T@Pc2p?|0v3*j|V!W_KB6 zqr9TgYPg!|5Fbv_F{}doU7pP7h5)wKK~rQF)9vvZVx3oP!XSlNYI;6 zz#kE>%YMM{myv*pf`w7}k)=y*(Iq|b00aiW_ud13?_Rj@E(mzv z9e=?uaW_twEPi>)>TzjxrTU?i!v1(k)l$(Z#tsqn8H^M@T#?0&Djl$jPK_}mR^}VQ z%1q<$fBoUV{tx_>tu<|54DFX~Yng)%zSteMEi+xFx~f69Sr})g8|-$My?)hQika`v z_Kn9#177k+iXEFhuD&|g zQ-m$XUTXE?Qd)rV!7Bc;Jd`eF0Qsc3P}m+vGiS~?_phg)JaqzQ=cq*$U(BMSs=yc_ zoKh3`0%g|@lKSxQ3}qWza(cJ|+Vps({a5fv=BQ#i{-Tge^5zJf%Cn3H^ytz$v(1B) zzv6|yHD$f3s`7u+z-LPNKhSK^!c0t|2nE0DDdl!S5>O!Mb49s0PN}ffCQBBSm=^r` z4-`UJZ$xXk@cO68%Rnd{6*cF-I_PFIcfamdN>2emxPpU+?_~Xh`CSXWuRrL*KyMWQTM1i1qbAc z!*sD){LX=dYVNZi+*J;kgNMOn$REO0elvo<0#!}wkPyiVg{uXu73;>{R7X(k@{|cX z7-@rBsK=Ub|G|gz@*hjwm1775<{c)(^4jgKJlNyS+iWe$ry}@OI#GeQAg}+;(3f5z zd+mGZq*G_iyZN4FE1q73qI+uP%2iK42Xq}JU==-9MKCnR{VGE-5Elzlu69}tz<31n z@9nn;N(p}f*p^MWTG5wB04JC-eS25|yuR4{8SYsOX7CYVCyhMGa7iD1_yPL)-FM&g zu(UR-w`p)DQu4EycOQS4(Qy~vaoeqT-naOX6)(QMb|YTZb{fJsOkk~lV0KPItfEq( zar*Us{{wve;UC}q{_nrYapV~#ou&%xM33b%P@^V+&xzgtbMR0qICt07E;YOteL zwV94FL6!?WB>Q;*D_Yw(vX)sthLhj6<+foySe4Iq;5vMlhvCdIpS)z9bGv={Zx^%Y zVA3*BD_9uu&3|^_!7k2K=7x_nl%1ZwG!6Ow>D@AJ!lWtFjywLulTSPQf{W=bbJewW zz_GzIDMGgvhIqs*^0)l3ioJdNulNmr{fr6PPCP9V2kgAG9FZD1g`P>^CQ044&h^3) zxIteyR{Ipi3v1BN?~0>sqgvJ06@fX9tnZF1*u(Q~NB2)%K-=@RY5!HpoKPau9sz}vY+J1d| z%k<2%lTtV8H!Mg~U~$)qbq8Qd|2$hN%oOOsF`4(o@HeTuLio$IwQ^sWP}X}RxX^-%9h9a(*XM1m}09c6#S(5`+x|6j6=C~fNc#Jmm++O9c zw>bAv{z~Cie*v~ezcw>T1z*Eqafkgqdh2s_J!-A8e(fLi102xYiQZh#t7LFsWW zoh2f59zx}t*eg>Ay+W8ULxJIk1%kN(Zi5%(O{(O*Rs9xzL*Pc?KViYF)(L#T|9rra zQ>I^V<<0j!{KN_X?69;eo-$D4Dp35?Q$%e-lE(Z@L}*-(@RLIMGWVJcUi~J)oAtwb zi~heK)AM(;O~3Y}bvy&K@7D-mT7Mb$cQb&a^Dn07kHGFaweJTXe)z!$@2*+%E(kUT zWrqIsTr@qu_~P@cRy?tc2+8Q*+itz>u0_jMytw-PPqu8^DL7HN=-uzYA_Mk*v-4{v z^mMZ27Ao)hX%~J|Km35ll@@5=ODsxQtWTDsAJL{uVt*1-16-+psXU;6(eCL7ObE(y z(E47>HWU1~za$hiZNT(bHe3l#+A9e{Ngv=x9(i~vWF?_}V|s?McValN1c2`b$o$=V zKlHup&fD~So^|eNCrmkJZ19^0tLkGVc=L9q%H$J7QUn)(ZT(f34RHd%g(F#2P#G4D zjW~^6Fv~etW=+S@9>fFo`h9)f)^&>w$l1Rp?HnUA)h`Ub%v`^|xZFXow(7rZJ0+KG zzE0KG7g+R*mW$##%l#34f2JL4@X_|~Sw7gUEQr3p>6&=RVVItenLHKvo;v-Ezn(Ye z5{8h6zqIT&0HXvG5h}qqKoQ&}$s{*oGp3yembU`8QkJqJZqPbm$k4S7>w&mh@$6pCwWAR1=JCW@mH3HY3!2M-M z2AAvAH7Ig&OfnbnI?N>}@zDACJ>N{r+{6+oR_>1rJ^y3K? zM{6T|BC@2z7tvV-u9Ea+4uV0J5Du0az#7JE9c}(a3Sc-3bMxu`GFTAD!Ky=_)Xkx4 zIyj!|8-As4h>$lmm1GPjys}1lqL{D3ULX_}0E6@SMur*DUtO)NOku7g@Zd}%=eTyz zDg#L{ONGY9z`+pBCc7pdMIA*r7k<@n#aztW#b0n)=-`A=fR17$%Q+Ocf*wU4KrDI! zJ*bl)aN2YuZTH%%3%|$)98VFC?q;VPTOJysYHtHvSwTUvM(xX5wv6dOba5fE7<^UMVUJjy?PD5?A)N#x#c@F+cBRA6XYgiqs5|!AJO{fb>QjW&H{AX9#iMaLJ zyq#o)Ey$7+z9Cz=mQj=d2V$A$^`Cb9@zbVGnZ!^~2y}9*2CjWXaNS=%w6PQC%5s~w zHQif!{Tl^rNX$R}X|GWSjXmznSy$b1&k{zmeQMQ;71&f6PoC*=W}ja59KJ?2{?a%L zf$4i@!wMzx}q` z?~uZGk`^um!8nwG-zzUM>=lDu6ZT5ubG@P=ZB2YThZgf*Hv<12e`Q9{Q&_2`0b*d( z5T{^jryP4_D_{enHZx+`g_izLGfa2O9SnEFo~IsgY$zkc>qo90EM>=jF}ZT7andsn zA+yc)^c_Agw`7oskw?wp2S@A<$S2=)JJ~|xOPVOTSmhY^X7ZHdPB?k`>1Y1+obxWY z@G>=G@fQ=c2H2z_DVSxFZss>sX z3c9G!Lb5XgcqDUs_=cLHuHv?(5V9r(<5;0RhX*5NyP;zS>_Kn^jO3&Zz}^7v0(FO$ zpW-;#!P0!i;1Jc{*FL^Q*^Fv57e8pVZ%e(?)$G|2csAiC&pYqDbI(2le?__rM1hLm zNLQdMIPu8xLoX>CEQgX(Dv4IqbTfk5LRaw|;s)Gtx(&+NTlrObSCB({V9sBEP~j_{ zD0wYreOdFqcJ*Y7Smu3=Ns>1ZZu22St%Du3d}3SS(7KROZj-7dwm(~`!EO;$bM7KW zI7aqRtw)SIrUk}4me5>u%(4YI_%;6#r|uNg6pR~ym8s}p`5XKyKB-#hS2hX+iECjE zRYORXVJJqaW!|d_(D?3wbB?IO7=%4MS1AyIaKgvsP#{~smz_xgq+p0_ zl*%_&^MCc~H{K-t#<~rRx_}2U>etYdJMq5)ZX{w$!DKv~HW_@w5r0W2U;e{i{I9_8 zn{TXsgV<8>z2fM0LuR0$RV%ST-?#8Kbi+-z+;R8f$DVoZ-H$hKgN7AY%f{O-!QklG zcvZ!1sv3YBe><0~;1>m)_F~kpIRv*~ees!*xd`1A1;0%%XaQ`Jzd=4q831qGK*+AQ z-bfoT-IQ^Hew+@yCYpe4{SAO=`~|+Z-%5m|H0{O2D2Z=pNQwDZqJB?5Y08A74jqAC zU*4vCI||pQUzn<9t^Vy0G4vUv6sNk`UObNA%P@Zj91YcKQ7YU1%U;9ZXFl!19lj1XaK*@+v`yMa+dIb{oTlxS zw!ckE- zhWQJ8YhVT?a4BGHxQ(Tk7M65gDka&mbMRTbse#c8J5S zaaCIx$ctad9;-HAcy>SL=McE~dm(Y2XU#$TVtGFI?7yBl{iJD=9Rg1tA$cQZ%XAEWn=P5v&oU<$g@-J+ z?AA1{9!lzEky}X*;~drr?X9X&{zHP`7god`%<7_`s4R_R%$%4RW23TUCAGJ;_*+_+ zttzR?n*L4g4snLg;%qW65D4)a3hQ*S#%hi3suGSk1RIKt$=o4_kDZ`#6zeGVQQ$y8 zTUueuU)hFP=~jE>LvBKQXbO#jA#|rQoT*!Tb;>%4(y+}2oYl2TW+A6x$fjO0&cXH# z+)EK6TVXm-)Y}Pk26-VK!jfzVdott|cymE5H`}?o=j5aK%cePB5bXZ{A7$^scU6(* zYk#5BbAB`D^i12fam%7wt_uv_vz_A=lv4z zb^Y&JYwri`dCyzQ+AFWBwf9q3{qMT#u3~E}3WeU{uc-Ga{7Yi5=a8a_DF_hl_zR=! zD$7mIXGDH^}#%$YTP>ZCDDJMDLtUxMW2k}P%vb2FNemu-2mT_WjqPXv5c-?3J_BI*`~2po*RNT1KLh;lx%d8u*FL*#=LesE z%iW`V|M=sPp@iF%`z0k^!+(au*r0L2aw5XN(Gi@;SHbV!RKNObA()RIJ$mGaBS*gf z_7DjKqv5~)`tTnbf5|_x`p;@*Zi|r{1$^j>Pe1wi-F*$fgyCqTke-eL#ss}q{VRWQ zse!-U7|*gbQn%g%ey^TCZ^mSe&z<@$u^W$#TJ6PeaW~%<3&A@~-vUhIiL7x|JY}_q z$_Nm{n>xVW0ndTS@#LY6 z!4>U(?5JXo$Vr!@?sLS$v%z&;VZ5jN{^eizV~OFp8*y~ufWB8;dDYd|-LN=;6K@ND z;jaC=rifn`U0-NfWA8LdR?N@QzrEwL5KfZ6B3L)92ONeZ$T~S20&9lW4jqO{P>D$r znb?BStMHd=RG+;F7MWcVouOY{#(`3zVm3Or-7JS$_=G#StGTEoOsf^()JQUxBX@+q zF}8=k3Su)-alFV~31C|SHY9E~L`ZiZqHDyr8I5}#3fPp$AUa;f?^*3jsAr>X%$YS~ z+QhLJIvBMu3UL`OWK=|*s_50t6h#K8iVrj6W=adE8@KohZk530RHe*q{ME%Msrw|9 zLIZDBsGq~%rh%z-qk5?F-uX zfZAL<+N&F@cV){4N16wgh5r$#WrOxq#W`+L=UzBw!X)@>g1>ZZfz9gEEw0y{i;|$S zB`^U;Z3BR6+W^5bBq{6(6b-Z_Zx^js{G|kB-JBNM%Pm`~pCmF-q*)MLLm-BCSygIt zKXPVSGp^P~4Ue`B!bg_2bc7p^temKBxxTQPmzUOyMCSH<6X9=ApEb|+CG(EiuENxk zJE_LGnN5Tffv!*O5+L>sn8YZhPRUQk%MAWbm^x$D+)L)poilUBRGNbH0c&_KvqfD{ z5cc(%*Zd%~G|OLxBBzG0mYO@+D}YB&z4V$}?q2!$Q_i0UfzzwGdGm8vqjw;H?T<|; zN*9dM%|Kx%)ytf{yY{^O?)%8!LyX{|^YjnSV(`a5If;-nFZ`e$X6N_cN;d`{p@2V& z{AK1OqGr99U>@LX?_QjmFgxpV{VG;(h9bYR{e|bA-LU52756MBDA4W8S3dsij@_D| zouep&cJZwCzweKLQ8+4s0jp9twqv@18L@=V)n5(Kfjjiy*#VOAg|7Zz?vjLi*x|#6 zKL6tLgP##T^BbI?xeJ4YuRmhKF?*w!Sl~K<5Z{aw2?LhU4YBqbN0B>`0Lk~Ui)Laev2zb zm0knZ=0HFKw1BPQMa-CnXqMGq*vUx)7>~T9zb8-Q$S{7*ln6eyxiB>SaF@jqc?iwh zo;-Hs6GxoeAYH)B-CS*U_>Q(e|IC@$?V9=Sk)K1}Lc9Y!&T(eElT9L@i?iDV=kWy6FVXRE|5{v128>_3%3Ds z+mHe76>o+zvid(&X=VZjjStq<+C>pKN~~sh&L6CQ$Ns%mhFqyD4ad zCJ-Vd4N{}hdj5K1&X9RzE2s>C?bl?dnpkR)Y0SJVPdG`*8VTs>zr&Ubh&{>E>}nOh ze1wNA+@0H^rp;Q6`o8h@_N&P4+xqvx#KMJFCvZq|A|wgQeKkG%7?z^gM+;*g=t;?@ z&#c7T=2%)jQkg&TlWBJ}+%w^k#bGSf32k}_Im{`i)X1z+6Q<6bGw;%Q^JooDpET~m zbI)XoLRB*_jqlKROVVh-t$mF4=inFA0^72Eq%LO|a1QnS;=cy4t$g`4ZrjIoR&))3YZ;Xxk>8DQ1WG}Xe zcOoQlPBLC4_x?#IXgGbaW+T*4t_j*ml+Oxa0$Uk@W8-@G`^Y24&ZIUasF9U2ZmsqP z-nI0W8&tn^V-ZH>WJaQkUjHx~YwNGq9sVsBfBl>0OAFD4)$f2V4ITBt?g9&RsU&}k zwv9JR%R=r5rq#|yK8{pxZ;eG7abjJYn>XeS;demZBJd!aZLPA&)vSzc1$f7L5SeKC z==QWjo^nj$Hr}}}{m&jaw8N9yCTrX%S9PC_zWQuXB{Jlm$=RHpeA1L@)BVf4V!>6{ zNMC2hjepS{cN+8Qe!k$LlpPwQ8-WF>0#OA#qW^b@zael<4qT&<8oV=t=TbAh2^PFt1VQ%TBjM?^O#I>UG5oofDjG zx5c2+@Jw8)C|!o@X1FSGipPu@OVG&i<0nj-42335WP&2(@!43Jt9lP!4QAnHrHrc` zZ1%fzLW!ad2yBU7lDH8uF+EGvao^3)|N^0s}|GZmvbBP zT=RNQ)jDnqgI)o90<=cttKx%#mhZPS@RG~m%r_pY#-boxk7Eu(cd>{M^iVixA5j=) zNp{S55@q0vGfRM5{Mza5E6%c-S~gfLhdlKJTSBxG@V^{4Y0Aut=UsOBCG+M?pE|xQ z(2?m)GW)*L!pRF{n($V2gW8y%t?K#5FGO!Fek1(*&G9Dz;5iF!TE6nJ4NNBQ3_Y8k z-L%Om<(WU;alo&>xzmBUjQ>Ubf?u4YUt)aHtJtRBd~46!?|<^?7hfGd{4GrU;fJF~ z5s$z(_&xH&k3TT{==ZVi8hG*`-M@N16S2~fzX>J%uJNSz?%ur%v-2xEcp(1Q1Onk> z+w+^AUPlM;vL)AFwP4ZWr7NG@zU!ke56fN$8ULQq#)p6Zdj}kU_x+J0M=^IRyVc$} zV&RGP*Z*YXFXm_X%eY^}@c;h%|7Iu>_Gc~Q4E>Gq8GQ~_mAFMGr53M>fN#Y9{O|x;Euw& zSRr9?iY}L|2*U_O0NndOm*4a7QUbS8z+SEiIz$6zvDgM=%?7QA93+$~-LR&mAz!!% zf}>Qy?vn8CSOgbCI{^ET+(q?V^7?1;m;*x(?FBH8tEWp|*0f5Scz!ye?bc1NanIj$ z^e)b<3XQ)Zu2yJM#`-SO;rYt>^XDhh^Q7@(GdFF8hA=qBD8#O*f-<{l#O84h&YnDF z>eQ)ICQlp>vd_~$TCM`lpmdnNtT#G$qW;hK2!b2ycrUN27OIW1 z^p;Vjn5mC}PmHd8`PG-Vz4+WS8y+QA6w~z0yKK=-cdgm-%Dw|%8DQ)1;ltk?#vd86 z%9vw_i52=kenhsyN{9)7ab8X=$^iI35xoYiB%y_kdxeJ>VXbg>hQ8H3O>9h~h)y7!QVS>z3JKom(HT^fEWUdkZXUg-QVlb-|p}qu|^E#?|;GHPW|;Xai!o? zz#6eE*bR2o_R!Kp-R5Ae+v8_{@js8mnFtGcv#{M)xpwam_kv&9+23dQ=B)SpEfGE- zal0S|bv-L>G4z0cu$mJ`9_x3RWBx9F^IJN7X_!a)X1vj?ITz2v@O;%Z*Waj+bIt|6 z(&bB`(bDi204J$|gI@p&fSXrzOtUN$!0;D3|3YGK{Icw@=mfBiTZPq#NhR=N-Go)L zO3*=SJ;0!^$ynv5`j^xsXm_C(C*=mH+@$Dv`P+B*c1MET9>r~okJ=SfhxcWwR`=$~ zUf%N;vode4a$++=Lv!4o5xL0U*qI}Pv#PtZx)=Iharxz!Gtt8IX}}b?W;z6vuhFSG z{%U3pjf3BD<0nj*FcAPVMg;zXUn=t$kF_gOi5AUL*~(s0^kjC_VhGB`zMj~{Un^UA zP#~2sU9w*PIe;U4*)5v`>|$>L*r3B&QDX~*f&B1HI@V(H)jk_}W*!Bw9oEHP{j+0X zE`oUE9DD@Fjz#>^^-c5&6|dUZTx%t50$7=yQ8f~SPD+_j{8elA*ySiG)D4Hkr63lm z1=Og=i0i;dv8w0A_lJ>S$IoK}bE25p+o&tO1UoYo!pHAoI7^Q#Gf)%m%f@3-J7 zKv@;Qfo~nb_ME3f!M+ucY-F$Pisrgqr~d+f^9!i=Mft<$QyGv|%`pZ>Uod9k)EU^p zF2D4Wd9$ZY8hhcn`El84ocBdeeQiDo_RHU-;%_uns(5}2e&ZNWq%!UOlg_+w^2G~p zy7R#`8;O+otP=)kipBx!<;20#A40>!v9sjw+xzzHp*t1#XU(}gc5K_mjP*O1 zwB9JtPp@Bn{~b3jx@`80ne!Ii`oM-4-u&S6LyXg9uIvt{xzZ%PF6?7uijzJJq+)#gP(p*TLLMc$$)|MpRhgC z2W*Tj9II0}-B)z|{%7@&T)2t%=K*FJs`* zg3IPy#Pncirti1@TGL4Ki>fb&O*d-kG4*d}ejdq=+6n@PIn>r0oO;B$5^@&n2Kz^{ z?`LC-y2HZkgIoo(fGo|0(AU*UgR`&|djl@+?o+sLnz!d~QFy@OE+^u@UEIog zY(9pbHDcBCezwCs&{y~}LJ?;ejAG{?C&tn1JAIaaZ}TxcUwguf)d+^4Ff=(Sz>aNt4Cz*iq;}K?Q)~UmE}qQ?}^a z12%`;8Yp0PMGN!EePVoW{0&kBNlOxkihW1|=g(N7W2(PxHk$Tr{4J8e5zrAihMp9e zVIiaxa5Ni|sm5SFOad6Fg4Og+G9K%E`@j*u=Q1=EI7{;YxK7iMo219GFs2z1iH5HO z`d2Q?5COtz-HJF#&b-t)eJpn9SDHDlXq@bRix5(VmOxkiDH8d|8dp(h(Sw1>d&axs z97CQse(W3~gEETD6^R@zT>MRsvTv6M^G}BRujNDW>rS4ZhnWd;ovbwS`T>(Uz)H=x z#Pys=4|%mwB691??)VF>X(BYUxQEU<`~1=4CjsEOmxjNS^~UFW@V6CPgb&UC;-4Qw z8A3WMwA~b%Nb+T$aKgzak&~+E|LwOYo-u0D?D>oDT(SCzC!fxQJzE%#^x`(H!Suu` zOkc9w7bHHvg(0u_X%VR7wKsO|edmJ%SfA}PMKjWw`U3*^Pk%D@#reyw=+*}rES}{Jx~Ad%DZpA`iePB zdUDaF*DZVanV0tx>f_MYUozFwmyQ{7DS$J3!V#e#$!gy%^A|DL_wRo<43;rD5Wj!> z8zhFP>R(*8M6bEV0qdKuac$N<{wbc^-(t@u_eO)(*;?=CKlAS=9JXSs)&l*`KH_j_ zfyNx4F5ssNz#BJgeCkQ#aG-#7X$8Q{kb^Z5Uz(e*TX?y?SLe}je_|R){#h1d8*^zg zHU7e5R$*8G{0k8Kmm*2fBU6e&{jvzxFT*+j#*Sc2D|5H6=Nc>j^s8SDu;;egGoNjx zHirzsKD(tZmlD{7={jlUk^j4ob`3d! zzEq9zxvE}YeXgcVn=y;gzL%Hb*>2yZcrxF6|H_9Sd1Tdncf#NF|AxFnRBZ<7^au|K zZ1;ahV7Lpji@v3Ifp;Wu9OmI~z#Y*{(~XW*+=+wQvL=@XzBv#riUxm6K`;O=K!%fn zp>|(9pIj_%UC6lP~s ztqO;6mAIpg%H=8^Rz#I-eZ6q_nyatE=8Wz|_?pD;T=09*H0;S!r%r~y^aA5k)r~e{ ztdRz3KLX(fWkQ4^gTe0wnWe$nQ55;FRkM-4F?I^FN<+%n{zsXY18o_h69A(Vo4lg7 zMSdp1F3}SvG~BlKwE9y1I^ivU?AE^x!3{@jlR~c&vuQA7Y>s#kzXf0skhu`ZwB5lp z37T&eCqajrIe}S;?Hx{WISjvB@C*P9V#8hu3{Ew`QN{cl&(@PGbPjw^iU)9`uJz#@BiH3qN$mjj; z1RDkQjr)!X3ZCDC%>+B!=`^4NpHuir*yDBLnHNr)eZ}>+-NQiJr=DfLJmPT}66+=G z&#%7r@^+$OX&MGJTedv=?55{D%Glst?|!uZe`{H;FpAecRTp_+K;pm{?p}w`hJ|cH_cJ zXHFhBcH+$Wi|>AX%PV_6qMz3EIq^Kc2!Ri!)AopoPFjZy!Qa262bk%Q{-6Kj{0pez z62X5(|B{?kLH8}ax$x!s{b8bWeewx5^3O61SULa0QGCdb5RJp$Y;URCHKT>;0siFU z58ovgwg7&aQAoU&&70$bmC2Bp1PLc-Cy#)@D_7im|NX`kyzS;2u42;gDPzxXL7(~c z^Y>Ur3cezht`zPP-&;|vvp$ain7oxTS$3;EP!yJINMBak0*bj7m_fPX?=fimr=RmT z-1YoplK0{v1Jw1XWu?QfWTO}!st(rf^e(HF9d6ANc!bYS1AvcO%Txcs(^JUYvE8n_ z`~THvmjyCrH%uZCVRt6fMoC{nZItxAu1R0vyW+uBtJgfX=HdH`zlndnVPTF*nG{RtFF2V1S5N$-6*2>(o0B}+R1jwyo=||o;h>IMTQ(I`l5avS7ab7 z>TFWCL=ywz!ZE{=kb-zdOCmrdb_$aXz=%afmIIW^wut1k_H7Jq2FDJ~of`H8>S~b? zR>i&>d1{Rv^DPx`)FIVss@wWgwvAoJEh}XBW3AhCv1}GezmaII8`d#B;bZar)Ea!8 zhCtU|;Ip#lqcb|j&?3H!vsGjoL|c)QFF1Y*J;lgg&vwNILwbL;f6CHAGt2lo2V&qv zhOtg$DCrBov_MDZJNW3d(=g)|bm{+q0vl;1{0-j$rzzOQPUX{}S)_2}FV9Kxr6sdwnjA}F1#v9IoZ)q} zck;ReVEx?eCQnO;Z`f9a7jW?3Pv@;-Mai$kH_RyODbr?=X3n5fgo&1&DUq*0JAkg= zK8m8{F?^@_lJUd(*R<~Qb{w8|ij|qCxtShd&^{xjW-LPrv3tO=- z@1Tbl>H9MNP%pp84${^wo1b~=>1Q@Q_uTVNTDW`PJ0E`XIe{lppPF*#e+j!`ukZf-`#=5=Vl!*u2gHuvx9@%YnD*`A9}<{>O~h2L0kxY&Fx{$8 zJ-+g;Td$r+tf&hv7&B@1!do9$yXBSL?|%64f&G}h4-m^uyNJo?+;2s~*Au#*;Qe@6ZqsyYn^I;jsafdn1E2M>JmB@Kqd-#Qyo zdVuLAM#}3}h7<@X0 z-M#$IrME7==1TB8!5M!~()wS2onlw|+WScA7#yp!I~%=BJj{HI{fk2f~%Pfdutg8TPh1tcIdtUX&eaeei$;(AqBf_ z@!$U2e;dF!`O3q)g}F->s(~@o66l}uk5_zEbu`*n`r6ucw2=xhNehE%?h;Xt}2 zD~Z8m0TpQG{C1lHuu@mEx3=z(H;*o2b2e8*7x$*;@YyqqzCH!;n!xal68NSYajp`% zB&Z8_uUg2ao>um$&8>9t#dGH}$RqHbIb*tGkL>;(tFx8z4g+yZ_J?LjuON0rFc22Y z;??@Qagpj+>S$`rrOxCEtJ2FDtX2IRAp~XNaA_ge^Q7)0`>mq6Q#+@Qv(cdfFce|^ z11}R~`>VFG9q#&<@0uz66~O{a4$95qqt!V4h>I?ns@zlos^{9Qra8bb_sp{*B|Fi` z9Y_>8EDv&3^B0Jtfl5Vm1cQTlUq6(&x(0_Zh|}y|De2H+H}M{)hYNFeUKww~PZq z|9<~Hc3VKD?-EYQ=t?}V#4q$E<|GIv=*CAlUwy!=gM0VBP2>&TpP7DP4+>b1E9PC; zvIP(9O^NIH#HxF4yY4b#Md8PI&gdy~7u|aQny0tDwiBo850TLz_#hJ+VuMD36Z_Hz zz>gXFq|dUwwtvA1nkg8VFc|!@Wrib`a{R@EM@Ru0WX*`g) zB_)bg89lBuJ5KcOJuuGJ=IiPQ?b)51uBptbs zcG=TD+EI58Qhy1%T+cnb&!&Dml*wLGwHcE8ETZf!Mhwz@8OXL*c6ZE^cna+G@qGNM z@EcL=)6GK8PKzRis?C(H&rJV-|Bsd6*W5+Vxrx#+G=daf7k{xq-^3a`EKYiZUe*dz zZ;{J`-$2?kW2@%D<$DExO*qM zT|67o&X_TC=B(Ls=I}p@S(u(LBHS(`f5*0|1sKtbL$la1H7e?r6g^v2H~~4*ugf{s z-YUJmn&ld8w>sTQ>2mV%Ze>|c=WFiHqTOB6;f@nIA1?l2AJB6A|G?&W8;8#e=s7iTh;KU?;lO^6|isyyL{f@D}rxHFF?s11$ zUd0aJsT4fc9+{{9rTFsRa(Ywsuiu>D9VF+S>MRox^2OiWH_&zAQ}X~`TavIBam=s8 z8}ubsak^z~3&`Zf>n%4Yw%3%#mp`if6a?@|r)br;HE_03Pk8H?#;`yWQg{`zBw>2cYTgo{hdufJkFTK#r6h?@9Ja@)z9F!C!BJ|dE=+eyL!pp z53Sp@l^~QaIVTd%$V@X(F43Ebw5WOY$)}&i{=DP0xAwmO(E-NH3M=sI+(CFW#afHH zJc7Dph^`}h=vLL}Y{09JK9s;XKkIk3j{ues*cC?ey!8flZX~v*+)YnEyJ^!iPp*CF z-rH|jFlXw73(sbN);VLRI!<}j+Gn@!c=fG4``&r)!~OfQ7=QK!URZ~9f!3D%M+O&_ zxfriy1_9Fv{I|bjc?Q4#%R#|(1ZTb^qG=$3!)zyrz?F*uNTg2%`d457{(BC_KZ}4O zAei}#olqhnI|!zE=nE~-H3rF0nYdt)@8Yj>F>KtZ0A8~ufv_H=JCDE{H(j?7-{zfC;CwlKwyA+;C${_}r{-@qz_b5S@JXGz^>ZHc)- zYWvv9Wo!g^_0eH>keARm{4Ls6;~|ZRwrY>?AochiZXa~d7Qn7|IT*>`2I67<{@=vE z8a%t!4D!sM2rkd3;qWYdCn9|rZG_>OD3b$^=ldU6#Z1(XKe2Z0x(!cl+WhRghwi>@ z$&$=JC}BGQ7kyQ;0dUFRiiVZ`U(Y0g-=Fc9ODcujQhi{!#(A%I#2O)jJJJEiM&ORS zMbS_(nA8Xz`?JR2taSX%J-9xp>qs8(ckqZpYYX5EZB4LNF4x7ir^B!C6~Eyx0j_xP z4c9DOuu$e^Ie)(B#mYPzAFC;oC*!v~?V{;0m^5R?bR-6LXQVImb?`5>mW0s*xBx7T z8c;C}TCI5woxbS+jUq|)D?SvzRFk1<04%@+wfE41=;@wQ{jGJLPC$}Q4I~rl5_t@F z?I}zvK%g^afdB?`CDw$E0B(QZ&=+Eb8mX48b8|c(Mhv^b31LEDN5+f4FhbE}Cavae zK?nmgb2hO!k=>e_b=ap-L7!=nfNt3c=|uD(DuxJl2cBp_aQK@iHWoJOcK8*!lB7V{ z0PM?*01khTKatrM;0O4_7c0e*)T z_XRMGCG7`%3pU1R&p^0~F1hBGd)GYq9HWa~W-?$pez&~>{Nu#;6y~h<#*h2 zqf`D)9DN?vX991;I@KD-z^R$28iCuNZ2?%_I1<1kAoervO0}d0r|zQ%nLGN8wlb1* zGWggt>Z0yuW%nIw1i-U~UjW=vniH&dpF_oH7;f^{{EWzf8(kXC$l&p;QAoG@k7MEb zkGCtQ9A^#^=!+|+6OSj()wCH%-^&tZvJB5lnPXwagP5JyJiZpg2F=e+3=i12I{aNm zWGjSfIaV25qr`7O+61u2s|UEbU^V)7J-@vIu8Xij$8KE!_7W~$9{hq}G;pa+4Z};C zfDPodL~9QQ&n}~4YZQ`HRFpc|?u|uX_`6tp@F4XV^Z zf6vGBY5>i^&pKLVf}D-_5pG!N^+kzLfvV`T5Kz*K1hJIBVl^^31QSYJ5I{+|oWv<(^(MA2IKUd8c7T~DC3n3e zf!n3LIG9RGreUD10+uNq$fIkQotfnabhv8KPRO*t!LNFh#6I~`{7s>onyX%JddNsjva#|K21V~S@X7eue|bn zH_l;IUz|Sys(AalwdULONz2Y*jmAx-xLTkwAW(`JLyr6H38$VtcKYQvEL*v5^NS4s zVFd2>9WQU+$`rRxBI#uB+9#fPV%^54H*IBH@Xmeo!|wm|t3zM^{u_tk#{T==k)uES z_#fzCJc#LE{T5mIP;hK$!-KeA8FzC2 zyqS~7GBw!A_&(DB7QUV0jmiy#!>YFEIM(B01W{xxJNhLnjfx$Yq!aY=gVaMc8^cs{ zUD^%y4R3^lxl4}My|`(6{vc01e>(ynQ;b0)f-~!~WBA)=AOw&Do6D3)xtojANSfJY##o%aWy{SEc6ce=QZurFlonGJ$ zjE#Lu)R@2&G?K)x;x$I(oLLYJfDyh@_a^&gy`n6{b$xHh=Aww{Mtbea?L_fgl;Q@*BmRaO=Kp9FZ zDt~)?`a*waXXt6CTMFAb>9S`P^wN;g*baStXs}*v&24#eyj-3U5_7+Lb?%U-#ov?z z$*EJ6`1OUlh)scU!oF!UYpWq`4g+UmX7Ih`715Pzn+ELKH~_o)WAnQ^>wLC#w&%x~ z)=q+p`DSe%*<`Tk*SAutXUnH|_@$8)KX0AP(AB4(%F7kNC6)jEyzw&^+`8hirz3#D zuj7rLh9z*93Leb?LXe#B^fhJ-+(EyKlRG!8|*End{g$ zcfv`hojq#eMYAtq^3^-;S@qac68PPZBY??7>#}w3VWv%>kN2m);B`e(^OFAZ*Z&27 z|H>NnX@?*s{MC2#U1vBk-qfFcdVr}EKP65kJkMl=q3`$cDsxmbeaa|cBrv0ZKmX(d zVsIdU36!a0+Ge_cN$?ky^du@63p5?TtKsi`cQ0Rh^L1BVV&JQ@iM(O&Z}As9Z9%I0 zWJ@X+d5dFWO@a(B#coFxz|(EYph^QuH3IkiDjt_LcW7t7+A|O&_d8kfj@fQ21Mm&y zEz;KvrvNENS`}S+JXERWp4?VexpncjUm1blL00N?mzK1Bq|iTa5p=KUXP@N3H;#M6 z@s2W3{1R&;F`h5IB8KNBw=mjB_&z9ofiK_cQ_nn0SU5Xpwm#MP8~t1IxAo@|#;W32 zA!G}{hF|GDurxs1`&;~N9l%Oo;$N+NQ2GYT9v)br1u*n2t}0B6v=XpmXw$;tG3*V0 zgW(zn%oQr;(##^bnV*B>;&+EvZmTi7PmVqI%DNWHM`7DJ-1All*J0Phx{Tu;J(}=U;}g4TGNKpsPJp@0WIHxko;Wcij{8+6 zJZgsHxIV?0Or@Cc&sqe*@6Z4tYrY^WLZvud3@(PJ$_*5$vpp=uaJmt?I#HKdltD2} zu#_5C`UxME$@L_Hukx4DQ9KEwqi%5JbA>O7bAn#EA30dp zq=?BYm`;%`94tNF>{kopI7KJ7Z27n8Aq`VD_vxW!Ya;+o8>0$L|1o8Y0*)~v&8jqs z#8~nve@j5yr176O_a61ndjjD8VSF7`n3PHQs%yCw#j-Kt?aUFkVd1L!o^l1zjJ77_ zbgq}bacTpV=i5NA-FN1>_0zx)0Upy%aHx`a)pfux*H>RM+ajmk#ZjKlyY~e3zD5x(iKm}GdG56c;7u<$;%M8p7oW%BdBgfA9((jrLMlG;$it63`uMu1 zHq!ySbML;O?{gfG598zf^|Olis;=*B%sbVp(KL`z_kJ*FXNqLo1fwa&7#TE?~HhUoWkm6HY$;>)`6=fB$X%R<+yKmXYw!Mb57f1P~rkN7j= zdPQ^)h7x~Hd`#@m2M+K7fSI#ci?)_@`Fj+%>K~6ft5aqyq-)wS=BgCQ`GD}Pd-%c<7 z3?xJ3bv4G=f>HP+rXc4qH(7VD`vy?U3AGS={o2s}ZZ#KYk>|LG={dO!X9Ksa>GRyH z`VsQC>0d7D08EBP61Usx9_;7f;coO9V5J?YUBB>}YM1P9YyY$8%P2-%B8c5LDX}(~ z+Skbi6J!$jKCrULxCp@UPj{d zuyO<~!^y%b^djEGVRpFNuHZVv3V9w4s{8TnPN2R&382 z(6vM}V%VEi;VpUp8eHl5%j*D^ImQk3+V)$FlD9FHH&X*}$pG2%rhVc%Uunl)sVmjN zf~R<`pPy&A%^4BIv@fZKAbU^Usrx!SRWe-iU`YL># zKC#EECD3ZlZIeBJAmW*Rc$!T4M*Y1eLE*E{peKNH<512F$-g`0tTEHCSbX>D4Vz!s z#t>Z8FUIF}OepX$V_8=+rTpqgAK&ma{C#Z~uFG`)GN&&J7&Ego_t_1s6LbPw;F6{O z{ql>?KlxDpzW>1o6>ozJ!{438lV)0noyg#wI1*!iX7thKr+MIG53jiUj+?HQSoD|j zo3}jvm@#$y`&s9WA`a)=D;X^H(E2Sez4gw4&lm%B=xe;d(gl2kL?193H*q8Nf&MFf zzJI}X41>Y1{lCW4P^V*mc5VnFc{oT4_vcS^DI*zE1kWl@(rCa^W%nc4+Vi2$) zMLv2L;cnP2BXDev;e5k7M;{5{%mut=^{NN%zh~Jk*Dp-qs|@`OeuLYB6zFB8k+`i7 z@mBzM)c6Ikln@SgU{I$Bvl=W3tsqQ7Wu?QIysI5qXk9={~Ci zm|ac&w$ky@c1XXUm88r0Aa{9;Pi3Whc*~GwNOC*;?X%*2Mi99-5DdMv?(t;EVeg7x z1G_TbcgjT$_od(W8e%owdOLJeO*ZI*rfyx zf9ce{@kS|nOZX^(3&0qyV=cb*7{OZTguIJ!OYl%j@l9084Enu>*^Dk>=9sZ@XYRD6gLOxPPlgzk=2hs{L8etmr@(Yvqjk}m zKuoK1qXqFb(jXXRh$P`edgYi635S?WPXr$nd=0h$DO`~u3Y!6dJ&?MWN>V*0ewoe? zBje~XNkBN6IZw4h-CD*)s-xmU%#_rt`r%{%N{@@I2pe+ZBXy>w=50b&BWsed4u>B<9p@}1K<+BNL{m9&#fPoZ3sQMq8E7pS>maF zyY;R5^WtYflgdWbxu~%+*4P=(|Gz!q-_M(P@uFMqS-t+*EzfOv?zznfx+k!r63N&$ z{VJwOdvxu_XP@8p3KK89^WlDcmF(b^U`kLNt_*~Q?b*m1#%4bBZy@!%7icI^B>m#HXV12-#yO-{xT7iju{%K#01yM%YvPY7Vz3bqpPeP(V% zre-?WyFeS*(m>F(C2*`JvbDpH06MxFwj-Nyf&T0hT(I8W{bq8G|CN4YSfAIeT?c>H zV}8c}>XC;YTyYP^XYtFVgEV;J`>a=nDTu0-expZm53ZjvYltWc$k?AHZy3}8%1@aj zse1AbuX3OuH?-1-+<}=RmE>Tz&SyPpL^g`P0o)LOQ>t!T`jSRoX7`AFTe5D>s!~|f7?wrW&VX?t`Hr@X||ETH3kUpdRhQ42oSBL2LIW%3mz@{+T1ncO z;*Wy~c=XuJJ~dOvUh*(8p=4TXV;XD`!hq#WqZ(&VdsI zb4TD*p;WcPmwi@_nM_!Fwiy}=)QzZozCjqUHsUw@JG&35!c%?wm&-y?rfLu2 zsMX8#SX{@2`@Hkcp$euB=3j(7m3Hz2h{X>!aJ#hadL*5fB`XcU^g4#!QMm|6ot_K8 z;cwH|#oy32bQKhqQO(`5S+p!&D{TXuPL;FOYtN=C*;O>9{KZu9D}QZYNX)w9@y87a z9K`d&1f}?OtO4vh9_uxa43hkYO2Sj{uu^pP59eavW!av6=McAge6jE5X2CDtcS&E% zL7B`y1v&{=Hd`Voy|;z5es#gN7xF)a;{Q-v?2-jc_nZki`DTew?VC^I$6>&<7TBYY zJ$44(Z|>>EJVjqX&)~?ZK8YJg8duYYuZK>2zHqZMMVsOzqYSKkcn!W!+g^Ts_d6djk6?z&8VC{#G&bOGl#PeK z`wnaL;jh0T_!U7daDK+`>iu`$eS0rMX7|wbyL*qu=Qo^h5c2Z>>jb%c$+5rBY*_o~ z%KMhzcH<&u$(=Cf0%pmzh2d}BF4F|aXDrpJr=K%w!bOCHzVESTcI zhh>Kg5x%*SVz?zIXdwLuiZ=S!(L{JYYktQ5{3-JjQz(N=QxtHXC|Q3X28S-t$Y*Aj zI0}DbfIi?LBs|9)0qo#tf^Xm;j;jvo@imVTgYw~(_umbE7hF20jr?WO!5Wu<`MD9e zINbOvkzMVWRaV5LX z4`-mqZxEYyMM_e|s*>i=U@?4ovhTx^J+jfn@9^{6x+Uln*X2@o)cVkJ_yI%f;@3gH zSOte{&xG43@yo2fcNuCUmS^Cr-8u9%EIA|8@x1T&+u}d>W@MqeikN4F9UYjU?F1h9 zV98TbH((gzN?(%Kb_xCh^Wtyy9A^o@hXAaoZK(q*ZAd9Yt1W6Xk<{{9>=!yjr=wPq#E<<9KHb9*pi0bxQf6V^DmwTM1wRU z4c4$BflKJ(QSl4KEJr%eFofqRL)-L^voaod%EWP_5TdEU&f^@7f!2-!FH>qCJL))7%$dRdfyap!&uR*LOKu zNtc)&DC2sDb-Fhe>k#H_i<)}8+;1|<_1rAu$3wkMmEKe>!k!ws2C7)~3t#d;L*txt z?1ff-AsHC~|+jWDK>e~nMkzR!C3;{rU5TW=|-VS`IWsuRQaw* z76e#n*5yPIS6VT~bz?!cQpsP6PQmSdAgClaQZwfpOjDrl zoO{U86ZL)0^}HJi%)}OcZx@_zy9XPx-hT0RN9P9CWY{Yxjz0xoKax?yg9p;=>6&}G zd;5RM-}5d&0@J8-%$g2)X6yJ9Pdk@ENDCJ)yLT0qHv}A}=an?#@5Y6w`k#nI@X%xH zpHTw8E%-iTR$r{p#^E>wbDat4JBH{0FT!%De?MjPulS|sSEsAJEOyc9i|T##WnxH& zzHhvq*wUGA@cz4)r{IdYv!)p-iU?=quG$Ck*Kgdf5(J+$X6l@UH{bi{Gdp&@w;w00 zuZTkV9TBHd;NRnf1zzd2ZHDIn7q2Xh&q!GDn;u{SIujzq&R^`#pV9ey012ESz!2QE3Q(_sbhemu&sKr?Xpg{=mlB>2V?zBT@>c@*#GhgT9O_@--d zy_&|X3kKexDCPMaC#ynlqg9X#o{r(~5IKfcJNmUxsUw0oqgJz7NGfh}6s`tvwK9y~ zUI_Q#8&8ol(r4Wz%U30;HiakEu{yoGxTI^{m}Mhvbx>z-pM~z6 zl+r~~?d`UDA>7}7uu>V|XQby;=yd{$SHsAt6}y@35)z~C8`j}M2c28 zvT4(2&LYjY2#eTxIi3MW2xt;lGyShjPjwcV7VC3Eqnz#eD^S1@LX(;w0b}({B`GD1 zN?ABB{*EKwwB~2nhgTQc7cN*&7JseE?bo#vlR7u^@d}NWO8Vrsx<{W!=`3Oj+RDlv zi%gmI`c)X&T3{treE6GzIbMSdmccYRa*<7!62dYV11{jTn7Rx({2AC3dMTTDAi>|H z6Kfol1SXFpDZ%>)pif57B?Y{oNxl`VDHm|Ujw>D2vs7b|L%s!GBGojnC-BWH=m_pc z+AO}dXim;Kp|y{c`%&^LNwHV(%?-Sc8|o>=60OU2R#=Y)c7GnI%%*@EdK<(;ziL*H zH4104`9zX*WQAMF-@32+DHg){1hc@Wrg>W=2}tV~Mzc@J+iVm0%5CLnP~g;@%pyuxBbxkUD2%TUa7C=q|?qFH|^ppuDKh&rrj?&h5-Hm zw`T?%;qtt9@4kJzcj7qw=4;^h)mNy^UVBybOJDO-Pds$rolH}(0A3N@nz1_IH{W-@ z@BmmTMKJT@e&@7_vllG6@9|A9?R@8>gLq zB{_ut9vivVXIcrGpP2%QX@G4{;8uo183ayZ#W@*ZIt;eo7;a}KV8$}zJN7C)*9u@1 z@CM{Be&S96jM;w0-Aiw|@tXN_XHKOtp&NJNPEr6`5*?#{>2p9U&9!0G03mF%0c>hl z$6R|qYrpI*{szDeXyI@4t^95Jvcqg~w~);GF{#n7qc4x=a;u%nK2%XUfs!TwtJhOPB6$Xi=83)mN0v;EZ5d*d_sU3m5N zi*LDo*>ZiJSJCfV-M*!Lp)dGlHZT%_SKoML%MZO4rUpt3+*x^@bgl-7RkU>zQW(1YcKk`!cDZ z1YWps0UlTr;cv4di{S`eLobk^3IMU9N>5qh9pD%}nYl0^Fj03Wj=jKh7@5g95bMS8 z_rh3-k-sG;s7wPD;gqBxRMlC}=3u5aP!5t<2Lh0*)HpXCrTDcwn#t^)@d4?h4hTnV z{-^eqC1CzEfk}-U({$ZGPlzy%A(`8j_U-s9ba_gb=-0Keff}l+IUA*a1vJR@-88wc zDo)8A7gMI^RP2qvRbt()to=>00XmojI z2+^~Q({SYSalQra9sYLZXWuY?qn|?GK(xLB$rL!*5aRVw(T}`H{w5#fB-v@7BlzpR z$glF(#Mdl>&5-2<$ULUwZxufLWfBK(BCZ@gvMy(=HzxMj!d#GpK&-_j?ae{LKqB3E>Y zxdGY!%KqQ|A2a0loqbF+i2mKZ8~vN9`h@@y$d^>s<0uzn{bMv2_ z@(9HXdU1XxiiQr-!nE}7=dnH?pf{UR(3;Qz3zx3&_wYAZ(;1+Y2^No#5(z6)D>7vR zVJP3rec*0$o|!9F*9`cN(_hx~-f_^j*I zg<~d6W}2e`etXmN+VwbHZ7T7*%_%X#Z%xAa=FXk3J-_z;|C+x|0=G_K7+e6>o7o6h ze)fJ?0$BVOe*<46u>2jyZ^$cylkTjZ;1agczfx2*+6xQ=%S1dhk_e%U#ds){pVgp8 zSky+|)@Ny6Tiro!ZtcBqDkO)%JWf~Va2EjAVBZ^Y=Ss{C2u#BMoOE?;&;gIl637>L~Z~)W7?$Z0ZuP%Ky-dkW_NO_iB_9Yk2=1z zOVsfy6=@XeShv#IsVbu0bnFhfiGf(W#UIS!PsUlmX#@K;m#Lhrg}ULo@|P|QO~6Q= zjL`@$vO6J}>BF^EF%q{tKrPEZCyKDA+ir0FVT~5UycDhARW7LO4qr|s)jk)RG~yG1 zsp%?9iUrjFWuySHuol-6XITQULk+Zx;>6Pk68a`U3FHz&#XSY6&5V}lu_Znuv^c&W z!J++GWO-F<-E?RB+3m7_vrN9hI!7Wdd8q1;??#WM?qrS@a6LD8%%WQrncS=grx$ko zEeMmD4#0fDMPF2={g_hDy!@MsP6vB0bK8=|u|(X(xf1Zf;*~R*R!uC$Z>oB6ec!%o ze^@o#&iL!1m?ARM!p$N=96EFKl>tj#t?HRH{ko>;S@6p`0Vq?O`UP^JO)Bu zZQo5rX}$ashRn|)Tn)9=CG)So@wU4jSo7qT9dGP@m(Y^?_v<+P8OkxiFkml^&tHAT zrgH^-^x^yEdj)!T?`Fu6_kH1I4dLHXduf78 zi$~$N2#mMbq>C5b_Q1O5UfuJ-fdijm0sra{p)>+cy_OZMa@WzmwW1jQ30JDpu|LuS z{9Vlt!OXd_(<4B(lE(%+y0z@;7xFE4s?P!1Dx2oAYar^a?l^Em6YApGzE0xQale{Lgmiw?h)O4jL#;0J2XQxqvvcKpD{i!zWMfL z9e%Mr$MpQ%^IKm){N{HmelgX&{^qV-Z@jQ>h5W_-JZyW0nwXzglfqJUY!WanBeagt z`cx$pN6gSML8s4nAbiW7ZU1lFuVS<=5nRew6`ZxsvaD(OR*lO+a0pz?ygB{A8mZOE z1?WcL&ZOKv#cKh$wCxb5T`j0XUr`%voPDkpvzK&p3mR#%QcX1|ffrek&+8pu?_k*QQ>P2<59 zdw@FxgQ--B1zc)nm2Z;j5A|!M=xvH_j)wxjSf82A-kUb@Tlh`g9WXh1JbAUFtR#$m z&$t#Lr+aI5?wXqqqu6rAyIK?n#CZ{#0oXHY6lL?Z_>!oyQ*V1ykZd05FOO~90~(!E z%Twv2C9Tj$;4ENaPYFP49wL z3t#+~qjfC-|I&(Z6@Cy;g9nk)u;5O7ce;X6y5s1_40a0fgT6Hkb2?#zHIIU*!-ME09Y7v9K`ZTs$VqUq4)DQp-tP%dGAVKM`e=* zy_+r^%N#JX=FDYIl6iCH%$_~RXy^ut^H({6L-Ve@_U7d)9^JTQ+iQE?VQi7}D;)R) z0waM-`VtosIeD-~|1#O&zP)H)($2Tu!r==3GQA-VE!(zldlAp8XP;WPdd2c3#Aw9p znTaL*(U(mkjj-P~{z_o`M-{>U#(3omCIjFH*FE<#PFPCdAQ(q1;&IV;`@@kRWv?nY zUB2jGHt4{W%Rl{*alJ==VEhqdkLdb!jtKBu0ic~;*jWv~)sKw6V8%Ejtg&hThbTY# z!w(EW`WDmm=LbK2mnc{Wc;bW^e1kE+1l=&|#{GBQar5N_`7)NUH5e(c;oy`UvL2!EgLc00T_GogDdo541U3j$j}RP{YQ>YG43-Yn-$=TEm5MxHB$8){ehXzD)wx zz99rRQEdm5bNQm2OKQVj9>a5d;*ECsUY9_VYGKsyb+FfTH3{}EWa@>5S6w-88bQ$M z_>xU8~vtyJ9LSNUu8T@|J*S0?hNa$7$AX!;ciYp-?N(^k$`3sX58{6j_WE3zRHzVcdvVM-sDHGS4Dh(y)| z9vw*_2$~qJ4MJuLYJyOxWCsh@6~{m(O8F#PBhSV9!ZM!$mwGcEGSU(! zb+Bz4GCsRxiu9GG;>A?ojy_T4h4nMv@toDvua`pI(3{J1J9AaH0{rBdg2Y@*Ibg2M zikP3dJ>RZHV>hL@R0g|<6A}F7i);|?zR(oMms3p>M=AT;ph*O9xf8!0ez<3yb$Tq& z^-JZQ*peaT7w50nfGiQp^}QJ@JbU9=hp8hIY4S5h5U2UUwf)P|&VR;P=Z_{P!4%Te zsf>M}JbCgY#|>Zx=kMkG(c>mfzxax4Zd$hDk@cImzsiI}?-7jBV9Xe9zjjhy;LDJn za(>qR>K%H2V|nE4f8_q94Edckl^z~`cH);tMg3xIwD{xK za%+ka8UX+H#M3V%V93%3pLllrTkpL8(I=RWzxoR0`ioek& zDI$J6nkf>GI+7Ru;(q1aOf(?q|NV@c*mN+cG!A4W%;jVDa4(5R{ZM6pCCX6?jv&4pZ*$ zVAT`kAFTvN9BiGyMPPTrqmcxaxFh#uyH~$C288__=5k%b?eeJZc|-Y0UOU)!nWqSx z(u$D+bsN7_w90RX&|^Q%LBDU13wGr|0lQ8a9CfYFq^~wUBlg>!aW+A(CQg~&8J};) z@tHXW8T3nxnGJe9OJ4>ZrRO*F1-}@f;qP19Haq}-m)*T$C1l0AJV?PQBuy%}W?iyy ziT1qKq00cIGD7zwfjhsgc9~}j?DCy1@tY+WF8($R+ymG#Mh@0ZvL9IfhOX>M$f`Qn zcpF=F;g{pt^2m}A1n#$Ek>-}=W3{Bag0qptWuKP6M!O=;b3R;zzrq*%7Jr#}!HDki zm((gH1zt%|-_Kg0~|B1SgL*P}B zjfhc+M92g>T3#h6R>5@AYT6x*#<2Sr>$CG6+HaJKJNN~_kx$m$#G!!lF*14*^}FJ! zaE^vGf`^{n>Qob6+M{b&6MP>#c1+RN{@vD@owHc5ZQ(M?rKFQ@%9aBKLQgShj>M?v zq-uRw;aAb9Ifno&x>R%k!Wy3cWtGMOStWDJXv?~`_`JQ;x;;aVq+7nnx zOJHsZC<8@GsTB4$u(T0}zv)4+5;opr8d5Tt74C=x?(f^~sav%^(3*_TrX^G{T=M<0 zi#Hy~LQr2DPvuQkbL=d-5aO7?*J#_4W)t6=e$TMn$p>w1+TEYuyT3+9GWq3DV81TL zMk|v?>DN!RX@54Oal*@hC4K~FIur3lb1u7j2?SpE%nPsV+`aFE{Rj3R`22GWxI|K> z8x@Q6{*OQT#KFIG{}QW_>4J7KW&In#SMj@j`*yW2p&PeserDqn%xHeo!b@l4s6?+c zKeg_c;M+IRXo>%`_zi#mCv(^Q_M|gLO`Ui3ZTGEt`o-6=gkwL(5!!y|%!qX4$oFVq z_#0vx!-`=?jN|>2L97(PNA1ShNXunxn5QX0Xl0+4W9sNoU zww=YV9wEQH(nE%o;!ViwMiYgF&(Nt`9r_Gt2UvDWu9ZBO|Z!*1X?kh#B&dZi_Y zfkzACdezOeu;z*2*Kix#wqcyX{>((2ui&Xr_UE_u?A^J2uOTt(ZV}f3$b2A3!5dc=7 z_Tshxd|R_pHv&sq&*)*A{e{$Ky&mva%$D&P+j7~T8%bqPXehkxbHh|v(0MHD^4cjp2brHLwVX)V3V@jvGIrO{O@;*k5Q@nh_{$ov)1Qpw22& z0834iv=lV?n%GE&H896&P;C%(a_&#tf>-BRV7k;^@u^1J7M2)^WME1TSFUY*L@{%T zDlt5U)g4Cb4leuNbPT!J;!8=i`SlueL)Ki`N#9&<^D2 zM3|a!z5F7{XKoWD%Ti#P->C<9o)7isq+Z5L&LMH*iS#yp4BxeV{PyynuNyT9AhYm) z3GSC15B;uxfXCB5qPLje{<;1rk{tDfal@atooDAsU^MX3`&X}f_QjXL9|S`|9z3W! zFV zZQA-Nvq34x0e`7WnYVbevO3-0VpeA`KSoA8fR>qVKOTLuW@Br2Dh#PHxtkcOOW~ zK2KGmZke1X^HqY{PD#2$DX4pLi|&r?=6n=9yK?l8cSk*cP)2rj`SY{OX`R~L*~e7a zD=L#3d4%uP%sJq95q-Y|-C&}ll@Af@xv5{ouK+IBXKXdEyv8_ne!DyO?Ax{D$>Q${ z_={H6|GAO2OwSF$@v4d|R_Ge9=0;$Ha5NEYJgnXd9ZqY_=3hntx9HKquhbnRSgaNf zfP-HZaNiXiOLSwc0B)%ZXEhAku)5K@lyh05wJQhHH%V7*&n}(HmmT8Rm7LnPwK^An zuj~D;0PrGHbJHd{l7~q=u zSp-vK3uCaN_feFO{iY17aZ+2wx!Sb&Tl95|)HtS?fWM=)9lJL}dDY~$Hd5*oS)=@! zNUM-HK`P{MI7Pdm_-p-bC!~GWz5ogq_i65Ab#8|>RcA|Oil?*?0_eGtET`eXl(YeT zwTE&n{N-{Bl)I!{Em~xR{_&Jv1&kYUPRoOG`tYJ2&&vzc;9B7ndoj%b#i~uD;_oRw zXPBz(T6SiQW$e$xC)FwDQ+40?TTO_TyP;igA*oBoi=^?jOo+qxn&;B z@ftivU3i|FH(#*`2I2nla|;w_-nQl9HeF8sM;K@BWUcE)6E9CDhgpAs;V;ka^S?iy9 zdc)(7K6L-GCD%AVpE07~uYX2lr!~aFU*6BZHUj_8CV_wb>)-tDk%!72`k4O{-)>!C9Lh^;9TZqwv!ZV?xR-O=$FTVA8W;uO zx?jVur5Q@~V0W;I=x03&9W=1dC^k&87%e2)fw*+oamxklXeZ zeqD-N`P+P)y^vkGyg@jp1k*7+Uqe#+vV^`u82!t{zn9ONcmYEj)QsscOBItkNGV+O zg)OWUlmIO>GY-e($&)9JckHklF{+@`zw);#D7mfxge_EsS`N8fK-pso^tiUVN|S-& zuaHLmdb3fZsUt@Rzjpo-&m;Z18Yz<^f!i9@b!jD;Lrq0h4b0DAXcQ0fMj8$4sk!sG z@e}c%;r^;2#}i?Iq#%`XUw}1ilKc%6(|~BZc{x_oRU=DZ(>b(1G<4D?$y>2<7YD<2 zIT_OukOof}?7`%@?4`MJo*M>>MF|YmJSluVk?tCauQZYpzXe*#3HTe!b3z%Y;^pMf)l?CD7HMbF3NgPw;3#hY=YKqP=6}`?%ZusH@$^e*qqIxN> z|ANHWCJcu`_W&4?xzhL73V3kB3@kEO>qacmejxYK^Z-BAP*Bt6`|!PzXxN=`2A#L( zW2yCLY6;S;k;0g(X%&r`FmVbqiO)2u&-^RrUvb&oS=eqSz~E7FJ>-UGIK7hZlr`YF~`cTc1ZVK0~C zFaLl6`iJ;ml^gT^kKTWerULn90wg8?jtkkLZ}5%&;){bcB$VY>WPQR}^=QWNjTu2HHs$wo6^c*lv4=_9VaFk*6i(>i zV8tpLw)4RXfIZYw;9DRDvEr61Wb1Wtat?sutx1Y=O4eNJdj)u5K^% zWZv=!)l|ULEG2`fWK^QD(OET-G8+-PbS(1&Pn?zcM&NIrU|)SfapvXq=j2er7Hv+)U9bj2UFq0@eNye>)6QYg<*zhDvH*D5b-; zcNt^i9xWlN$2->|^feQ-9~8cnQM0kN`%tpoQTuEefJZlMnPjJJ1+FJ?aSd1Ub?Cz; z$~`+qcx%r5)7ooeB+U{)C%ke1*I_Z0Zr#D-VF~=Q?u7?+>Io-jDgy3LS0{CHKo(yX z-asq9AB7Gckmg8E{H@`psK140dsVgvWFvPf6GiL)?ce0k9a(j^*A5=k<-b3V$5}|t zzuuQ1Art^2>Mg~uAxQR4#~o+L5Qm>w75}R?47;&qah5Qqj2aGV_67I~RHFW%c!LVy zkewcYxC_wii!$YRV$fIu#`-U^zQqa zo;wCb>}-DVg@%TH6ba#Im{diOk;%D zMf=)u+vfCD{r-pnnoyaCzBEMFd&bk;pXrb6LN-Wf^qz2noWXb6sOSa<>R9ojF4Pu3}jL8zDtNTfqZ@*;JZCL4G2D?^j;a^9>jsV$x+E|_?TG4XA=rJL07Nu8t@cIyHuWp@ z1+pI1hN#96?pzMylUPWM2d&E3oDUcnjK)aW*2p1ww6fQOmhM1t8;IL?9D4w@rm8tN zL{Cza0}&_!>@1@%W=IwbG*u-h06~-0yY^F=1#kRzSg7|-I@vdr97BoVH^WghKSRa9 zys^;gT5J`7sre9-{HtdbLCKi9TbbR#AOEX%{m(wUl-eKd+APr{9@m{Nek~_C=Kqdd zY}U4|2_TZlzpA$+SrQCK35UQMqXjTe41g_r^6Jk-0`rErS2?)b#UE=5?>r47KKu&t zjk2?3`pnsL=Uu+w`dgQ;!140_yO-U1BOQ{nF2aqO(RX}}HZ9M>7{j%GXIQtrbw#gk z%Gc-l#C(N3pVi_a@6-%B&h4!8$1o@FyoHNzyZgaMh{-`uFasosa|Ltv?R}fD8}Rs@ z$X|MXU&r+-!;YA-kM7b9Yad&UtMKyM7GJY){w1@gPbD@i{W~^j$&#h@yW}l*eZV$T zczZfv1!cBketW_xXPiHF@~lg*y6Mgpk2oS~=e`deM#Kmrr}xFg>_iGb963r~Fm_|s z?E)r7B|DD%0Vn3q@uK?ZeT?THeH8xE*9(2|;l}t(j7bgX``#gh2wEN&FXb`5(T7QP z4}ZF!4q!$AKfmeejqAkkowwe2^%Zkx)UYFdug(<0H`~7MmT_|rg&JwIR@lnEp3k*! zB;I^g}jBB&_b%styo;^}) z^0$CnMrGKW6adR#(tVBwHdP!-$t;BH0+!_itqU~V1-VIbw_Cpx{*sykX0ip1&$wc- z&z@kCLw|2W1ve?HvsJK~4|Yn-QmLHYi(JhCqU*=P&hBv?&6ZG)At)p~=3} zXg*=26fALAcPnubK`Z_W*jRk+B8{ofN;*}m6&+8NE}FSTr=HKjFOC~Dp0!$%B73#K z`KO$}_XdA z&n(WQkrBZg*vj6po6crZH9^|FVgV@WqSAyx+}HY@m#nT0E(5h-hI$;tSjU?hajO3J z8{uo=f2g9=M*ac`UrFAA(v^>1-m`pVySVx+Oe2a$RIvFsu%i!0sD0-1>S zXfO4isXLs{I;ZVYsFM3M9Kx)Sx0(?W)9m;?`pp%6v4o+8SyvI409Fnce|a7^Rsq*r z$?LFzk|qqE)--6&q?gxbpdM89Z4npCRuZFw#^NkE!wFq3zY0WT>lckOy>HxaMi#Pa;=D=(oZc4&HrzDnPRRuQG* zj$3ZHdcpk5=FOhr3?~q{Y&5p!(%{ex!V{6eHG=2YF(23mtS{5A`5ByWDyHyBGcLVq z@iN9FKezq0J@4;_lh~k{mC$L7Oa^h5#WkUk7HM6ue)#V2R}PbMip2Nc#{&I{u2!mF z!cyXQb&w5fLzZXUV5}-Z>@Q(@|xl$ zo9^o~0e_ixp_9K;82Nh{BY&B2@OA=ktXP?t&%*b*RRKIuJ5$cLxU9tqQa(IZpkhBD_3>LU?S`IOLPb&5zdxPM7*0vqMcKv36 zFZfN0k-36QLS=7bszW&!0AG{--@>o@_lnErOey!PR>7oW(wfrhCID9Bb*a^CcFyY2 zq_WhgiwQTPS5Ak*RA3}YmfBE_h&(CVFZ{JZ-P}toHBtYa;|?Q!Irq>l_TI%NFh3nt9q+C?)B{b#QXMRBq|ZIqg(ziYMWk zWqoQbUP#k?TmMTcHFHEWkTF~N3a};k#?eIf)P}#58VHC%@0TQAv&ozFMgc{^vz^eO zhMo+6oA*@(m9A4@U- zP)uQb!@Lv6eU$=k11YD@oOi|5i*LE(?iCL`wsxZ?JT*igIVc{_Iy~c0$}GR}d4BX^ zEYHiA-gfg1*DhLc#ies+&$x(5KAC8Hysbz7Xwoh)S0~vsZ4;&mNnRZFy^R>&AwB5F zpLpsS=Z={&^O7_;o_y}5H}}53Uyu@z`tUd360f<NqW@MIoG?~j5=P^__uhZ^ zy^r?O{rl-b=8_-?mipJ|nar_3=k=TTj=lNj&fSc3<{ZOAlhD7PAHe*~0N@ukZG7U9 zRnB&F{ld%V5_E%cRQCOz&~+Z=57%#^)JjmTdI{>J*uFSm>MjPmUO z%=Zs~@o{)}-)ql49R5DA>R}ULC82!RtXcD@W@zY{ghe@`cGW{s$Y^8;ELh76E9PhI z&;U4*JaSR^Tc?$;R&33vUP%jnBY}&*%YtM18|^D_Rm5?Gj`)qoRWl^3WZ|#6xcF$CG0);@2ajl{Z}-Z&%}xCU>jqa z>8K(J71Vn}y(3UT2qXkTs38dziYTH9L=n9ik{HL`<8daLOp;0Lnb+`tp6}Y{-1`&4 z|1JIQJ?)-*%02tp-?i3WJN%W>Xk{r(P0^Um48GjhorRu#f2ix^Qy>)lrdBO^qXRk` zyTYc>sVLyF;+N3p;FsteYGhx0gnI>L-9xn<2V#`q56PNf#}nDhS8|9q-E>Qu04_iY z_kQRckH_sHSF?eW7Iq!(a!zp$=4x0+m)%(mQv7Vzuv}eStgan!(e!yzTdRECV<7Dp zrAF7P+|jXsCTJ+d&d?0*gaO%s`#@*=HMnZS-@mDt=6p;yu|>8@2i{>`_NQ_c^?ecb z(u@NHWLH&-i|kj}pWQ_r34S?`Y_(?3xUGo~nd)6L?S zHr)6L%HKKj7Z9Ah}~%rnn3 za_Y0sKFbs%)t@2xQ^`XOBT+bJA3BL>C>i7vzNggmmitPb@VD?R{Z{zKf3;wv6JuvZ`!%{Am@DHy-$djB69{EiGJ0fivs@b zuVaxWE{lAU4Zq}ZM&*9;30;urH|01CfB&~+v()@d`mT@OC&Lx}POOJXzCe`s$Dc9k zgfU*GxBmQNPZCBJEC0&nBzz`=W_-W?rfoEI{$KAjHy-Zr0u%-ms_7nHwIbLU zdKu{8p1|Qw0jHql0twWUDom}pVZ8PdHxrkYyxr#gt{Q+nq7G^~x;k3!NXOs7feszL zliiBJiKoGF$yUtfyu!^6qaH;q9Zc1HZP85+z1M;F__fD4@;77t@`%v&$RP(eY;M6< zkHz_0L;c3{`%=ows9>T7vFC)pZ{Yt$|6Yc_AQt?_3=M%5zFomV-0aew0`B;$`57Th z4`4?ztX@h$7zCI7xrJYaz|{e`U~K1K1#kp0lVNU5&n)X^5)6HhzF-6|SPg$6u%$`h z5I9j-0$BEHlCG2*fpJG*SBYxzyE?EHud8wMt}w>gQGO}mt&?lqs?Eg;UFolu(EHah zz0C@hwI;8YFr<62B4vrc~ zQ=zF~sO$kmlnvoW>?FumyJF+!W49&yyxj(+uK%Ne%ZO!-ZSC!|Y)u4$6~I@TGa;Qk z6*n3fJ!%)w1Tdcl6X^*In>C*oG(Cx&11}+}v#g55ZHojTt9AVHUqiH8U>{%8#dq0rXjI- zW|G6@+ik)5CoHeMMl-JMfZ!LsNCV0nCVn+RQre_%xrrh;h58y?=WqcZqX^StsJ6_t z1gGhu4fY_gmtISRap_)Y`h#J8*86K-fklg!uHF9l)2}kzAA|WQNtT<*lgYU?aU2hV-Q~@L?N+1lLQM5{0~1T zFBa;T)LqD5t{(X^%M*sTrna|SNPm8{~>Kf#4GH=BBn?a9A`&@aij-Nd9%vr;piF+>RZ{n|jFQxd40KWJ( z{N28B{f^xaKdMC;0X)(G-RWHTTQEf-8mc+B5>PI4^rLCxZ#BIRCGe%Du{a;p($p^ac8GSV zQbTjH{I%z-sh&$N0;|vm#Apq?Ia!C$$uU;LQk}4**{!YfwIPM|n2eDbR;)@H5_CxH zF|lu#?J6BcE7cSAGPQCV{;9;R$bFa#z^sJ7hSm4#R7k2j*>5@s6@@u?j-F-F@1rc3m zZ@tHk;WqgL)_xry&u_$^YAz}l#Nh$~F!Q9L%$>qg;;+;zeak4-FFlWtznGsFE?Kqp zv1i}-kdC+?e!#%H7hZnm*rVImFP%G!ku=Bn%dC4Zf75JAg9p-u=qh*{Cau`SNK3`@ z)+(TB!B!AaSUTuoKUr$XXfS*J;-w_i)d+=c@7`_n?097Vezd{C!-tPN@x+lM4AA%3 zzC91^Lj7*pxF+MGEFm&-(ZU5#7zWRv+%;_~-rxzuJTeA}7NdZFeb$}V#q=TU(Zp7)f zY82wFAvX&;QR{o?+AU}R?sajueDEHaMQql$c5Q%mkln#@bVHLv$2xMdw&68pNeI@9pr|CMVkSxOT<`?!3RZj57FY7U7A>ys>TPt_Sz%{XIO`4MjSBo=sO~euJDb(AR9>58jH2_+FUL6=UbBHMZutOJq zIYOhK(WBatAuei^4UAxBNJZnw3cMb#jzIxk`|}mvwxoqwFI{bZg!#&_G(}uQ_72g{ zr!^bXM>qmJatli(14?;ys8RU{yAP9z2>Y=YT?Gk~xky?;X&9A=w83K35oGYrxQ1Kj zK~-}}(*jcjbYBOHa_`i%fkZ&rUgUcCD=+;G*vvA@8qnoGv{58?Iyh2~-ALlgl`u$9 z8q~#M<+wZxcG|&8>1^l~Rt)c?_j2eqHvY2M7MA?Awg$gIpKsJO;1PT7IbGDcM`{9F zuRN_EF0=BNS=|3-S(!MMu19m`&cpt^c*W*Np1Sb4NhBCz09w5M!jt>9uU$NUmctzI zL)K!`-Q;!=b0zsM&mo=y4};_ITe)m$QYe30dqjHz$Cf7nIAL1*gkUv-THp1oxKwmpYVKmXdrkALzd@ydoP|ANlI zLKyk`OL_eBSfzi34;L@5X(T_Qjq(u*L^MBF05o>#Vg8aY1RMIZ&rvtO@;ZTK7cY|1 z>-@{loj!JOADxcYtz5d$7_x~RD!E&+9eB0CpHlSyUR-)s}{x0VW3v1`zG0dMeA^p>Qi;T?=Z1+C_b+5v{%T2a}^`F7Leb zEB-u(-Mssdmtg2)mzk_H9K6;^_9vLrSD$B#THH2nI~&N~n{Rgr5&Fh28g%{Lml1zY zoGRpcmK(ECGBE zwq|Y4!vto*JuEK;tP2>Ub45<+#kEr~CH7~H);fQ?G872iKpPlqkwy%!RynC>TIJc%Hw)o!HngfoUVz9@HvM;sbA=z5mT!2B zWo(&{i@sW)1yMNGsE!#=Nukz@Au&}~+`pkWaZ}bZR5A(kO_g23sjIhDO@rbFjwg!% zj@K^rv~0A#7KCWlE>Q?}Xvqr|t0-PkO$O4sP>~u_xgNKIXa{t676iK>RWx5v^==90 zXlTwfwFh079+PWeR^CVJd_|wj zLbj}v!E{Y!Itn`c-@#RwfUJkt_ zeq){%lh4DTD6*LP5L(chQEL19pvw?zE%2H{)%6V2yOy6hn({ku{1Vp zEataE1eP~eeCE#RBIh?W%FG+nh<%<5{N~SJc=x6~Cog>Q5Af&bzxc&hfB%yY-gx2I z-g{Ooo;%Z_MD(QC)h9m{?`HmLf7fvm%H6saUKpdW=o;)LO3S9TNzmdvAnc-y8@G|Z zjay8aJbChzsEn0s)^EIr!DSfQ+(6Jr_w9{cZQIr@8|m4gMQhb69$p73Gf55@hQaga z&Y3+c9^t#t!jo|dPZ&=RI*yo>=r%$sn^=1exSl=-=?;7&-GLXZ+zcWxnU1do4->|H=^-zWO`u&mVvAA)S03MuJYjq|p58XAFz<`RAXIJmjMG zXIQ2M&pAg%V6sl0ed@_0YF~q%k-k&!oPb_uu&Rv6U6+nVpa7=1;7_2A z7u0g^i?|KDo&FUUqRDb8hyL3L0%xs@dMfoe5<{w97qmAg8fe>Q%yuxY6}7x=Rv&Gf zx|7}xooFw`wg#83OmG)qh8p$IAIsNw0~>g zXy>Ey{{UB{#pp;4}gik`tbb=&pf_!)4H7x(VzsU zkH)woc~c^PA4`e5Hw<>GP64Mg@IJI{diQFCj{7&gj|#t9pEW;MoK_nyIMG@Rg|vNJ zm>aq4R6?%q3x476fXJY?73td?z9KgUXyFWlo3yRqs&pOd+`sBwIXsfT$mF#lHP5Uv zw>g8wwvTZN1defFj>oCJsn?Oe%G0h=wf0N> z0;r?!h4bat*h&{GCRB5e34SyBy0+?#Mgi|qC3w0@A`CFB7 zt_)SW7S5nN3%CXps%aEn>gv?kp)wc`Yl+zs_}Q~xj79!d{zn08As90rc{F|cUHJGW zPM|9)!za;QmE0!a7#d^6w%?};w-BopS0$UmC8PT1rr;6f4yrJ@LC*6EoWTIc*Unv% z3ycn`?4x=*@iBH{>W!R@Hf#9p&f+$X^;-(pcYf_PV%U{sgQekv5KKpAc3LLr?9x`2 zTm6l#sHT0fVsH<08?AK2FA6BPQy)He@w?eN#MbETF=u3lA^jUK><=BjluOHv0{A75Z|#o@GWB}&tA4+$HRwDpL_Fz&%P`@Yfege3yUoXUkuZ~B!x!CKVpm~ z6JULU04Cieq0=O?HY)4mk3M+U%+==!-nP&3$tO>qJPCx)oH>1(4!?&FJp90pts7P? zL;6m;bK)IijVw38iP=NCpO7YKpJg7@_6W;fpI`Dy`U~hw$BM6`H)~+ZfM0Nk8JD!h zytUHk)WfNpXt=FeINRoV3xKnH#5Tp;t_afSND`rI3zMQ_R*L;QUf{;uEgz#ja&k7(5?;R}8-K~rLaK437GX6P!-2(1Mu ziz^H|2o8Xo0a^ej{>nrh^7lba)V_*g(m=ysD7#JkT8N2mrG_MQS%a{BkI=cLfdk&W z095rbE8s7xSTCI8YLTqe7DJL7UYcmCZP6K22q2 z>7eMwwUo0MCdfqgjjhwlJ;lgYDWG&gL<`^myUAbq+Zio|Z>pJ8+TZfowPaaLm&MHWIm#-2)~cDEa!s-G?$ z)?M-^x|v4u-rN#!Lf_Hg7vtzmgw2epcM>FeI~Q-%xCxW)oQ!Zl0c%Y4%Q${DEfP#O zK%#ELJ@jmpnD+z?6fNfEY%XIMTvC|hVn5zWzzP=YqDv6x>i&D-J++)$ZjJgH3XAxN zy!d|u;HpU*b+kt-0E1q$OILRxP0;xrmFfA)id4df5cglX?%^+;R|gj8(m-gp_!kW7 zE<h3l}e4 zdGEoOKK=DS{>#7r>;L+vKm6|JfB*S=ubz7N-n$pgn?0kYo8po;0P_vGBs5|89!>w8 zaZZ+Z+dVl!ABaLr;Wq?Mimd#UZ{TOeaZzFv8ar`{p-P$yx>(Ld(ixw?H%+H%cY!*F~NCHdd5hSMfs*<5KU5Q~=35*-~_6gG$ zt=YQ!@zdwtc<<8;iX?5p?$3TkzAJpY@Yl#JmNHV}-+uWy`L8~NwRAxOznGxGuioEJ z(Z%n+!=T0I8RE!Z%MLMki0YL@le8lqdSJ)Bo7S#agxz^EnN8@nkXR3Ul=EZDFTjQx z^0(~Ifp8w%0#Y?1;B+^P%@z z-!I5_I5&XqVCr&*_-B`K;{EzGL;AUHVsK7%2>twsV_<2u3HsGFQ5)sraEX(t#i6?h z)wl1_;^nK>8Yp=GgL|+(JLK<^r%s>208OvCW_+%&tA^j$pD{tBe?NHh?7{mtt*5)s z_FZUak&5B@(4j-%S5I$wf#obkwJUoghy!24uwZf&Zv4PV;D`1^`9}Cg``U2{{5oo| z;aO_sID+y2Zr>j22EJW?q`bE^@>v-i{VRPfjkGZ;1K=(SI$>Dw*XFMTF07VAxEjWC zR|<>Yp0sT{7`(O?=EEYmMPwNRO~IxGep^}Y;J;&TGUBG$pVdBA$CfMvGip>9Sq1Cz z@*z*-pGr{0WTnlE^o3awcgo)p_)QR1yumuH$^gx$KuZZ=>MZtI-^jjhNYJ!$x#?xR zzu5SIuhCbLzqFnQ!ik5sYwyct?QV#$E}OCEL{+J8vlt^C!Mowr$$-T%OFE9;;%Sug z)^{rTlmOQwj;5BoUKuY8?E@Tm3f@Po}drR$56`Uf1Au#gyR-`ur@=Ts~*NoYW z={{q6GBMqX$#e|8Ri{pyGU*OtM$09g3#FWuzkcOFNr;1LyM&|4)J~~#MZI4fpao=! z;`kMu?PV&zQ3r5d3n%1+b9B2<>+MSb}#h z5kDA@i>f#H)sDfP^k$O!xd6;9v@w;!UBvt>f0arFY)l$CSz8TU1{*;B(OZi1{2?Q_ zI06^-J%!)T?Pd*UfQ?C$rZA-GTr}gn`3n~bl;xtA$DHFZ9!>yv7bhpqA^Ky> zgOQdTZ94jz-#%un?&z6w7c~XE9R*yC`dt86AC+FHIHGVf84#kkDeY}@-uVdoMBjb) zisdw-7tWtId)AC;T6wW9Y31c$I1=pzHet#>^zG!N96M$1@{PL=Jo()Di=TXfLzm%; z9KlFSG+CUPOpa$}zxq2}m zgWs|3KJ4e~RU(1JK&6XAJC~^ z3|N@1*S63l4Lp6$MhU6Gxnv;_Eqw9Xq^@r)?k&(+BW&HUZS8D|%Ubb^m>h8c{lN`d z5JO-cT6?+4oV_R7V0^i&(Y|z;u^!IgAbP2rmPb3(y!lagP7{~tfXLrbGzl~8(TYCt z&!AS$|6^(wnu&+2G| z)OuDlf-T9F@34?KveUlC97WM$@zq8c{ASm+TPth7PkL#yYb9YxSl1l&NS`6qwl6%n zRejUMx6>mpU2%2zODJl97+{rX>gvP**aPkPOFO+78T&GaX8@J8u=R&mM)rBOMPsI6 zF^A8=%Nkgp&D@X^Nc1a>2b&t~gg@(XYjRa}+9>EVgs$p$ChGUDsq{g;jjeAahySF> z%ubpxmH{V(f%XN#&zBR8#WzHU`K>7dLOi)zjHNM)0|W0Bm$hyj7eL;MTzA5`q)V%N z^SYZV`=&bFp1~5XVZ>8q@7aBR0=~2Z@atL;zA5ed`D)-Ko+5vxX_LP(WQg8^Fz?M| z%B}qC;5WQ=zkY~P{FUmorP_@EaMxhIVc-bdznU>(!QeMY+!g4(^G-sR?lSY_oH<&b z7cE(~V*LXr-ulJA{_#(L`qLl(&;S1CKm7g|pT2r**X9+ARFl&P!s40}FXt`urZvNb z*T1roDDDk&zS7H<9|bqW6SQ^VS=&bNqyu0P%nhW`#Rwm?_{NMI&pjs*H3E3;1_pUU z|0dBu6!6X+n98bkzO@C3XckMn<`!R5J%D4{=Ns3rSw%$Uaua3EPNpn!MPqK^g7geF zze!!oE584u8%9lxD0<;YzN?1&YdODiWD1kn!0C`32s*`Te667ZJIF|m6TtuEmVqiiqA>4 zP`sfO9l)({!>ed{?xgS6Vf%H6Nt5uT2QF;Mf|1JukS&|D(?!`4 zufl7vpw0Q#m3AB>klNUpx38bhh)w&M+PIzSh?#zqzIowEw!&fb=bc4$T(#EecJOUG zoxfe`4f-Bc<}17YZZ-4OzWt9Meu7~aP8)sI^*zG=41rq-e&2lSEdUIEKmO>Q7mn=O zyl(U6E%)u(`zZL`ufCPBP4gCgA06BIpXj=_mm3m>_irRWrnyVh&l46ij zn)Q5hOjf!M<*TJ0U~3p5+?A|lC}5z-VSD6ZB&QSRM3iu(4nTZ+`a|I;q~a<}N?dA8 zg-bxpMANm!S1SH$kl6GHlB`vzki8Z*^sSQTs8r;=;ep~y(*wZt^*cWK4>^*z-C*s$50Q@MFs;O6v zuaZ%<4)FSsWbi=w1f{uqG^A2;<8lwJgPSW~4?ZI`x$i`50bjt)?pdOLwfI}DDTe_@ zzT12Vflab9%1*yr#k*!qpRRqs@pmCn4=e6D@bcgNZ}3a`&;R(>|M|P0TsX6L>*^&7 z1n`uJj>q5?_m1%^Ns+?wu*#5xIoEH$8e|+xo|-{>B(0wKQkutuL-WTrhNGI8NYjN& z2sPcfb^Fd;q^#ffFztRsBqrz`sK`M-iBuG1(aV1t@&0$c5hf^QDhm_Q5@x&*^^Pfe zBB2&KEq=^{WeRVM_afLUjjQjvTgOjZxNhg8$De&wCol%(pGNY+T+OSx0_&cm$L|Rnvw*Z`$t<|Z^ilBWxmq-Ja5rb5<4?mj3S0_o@_AK~K>{ajm zeeG3>xi>C=-?stqn{U7W(MRvRc=Q4Jd(Srbi@e3?T=r!koWiocxH3Yxyu!hC^9pN% zPKGSmONkAdmll4d1zH<)ihkgTU_CcH8a^B#xaV(mQv$%DFVBq+mX8z-SzEPC#Mq47 z4S!{^4ctxuD|7{DN<(g2QXPW*-1;CEwhjnf7-mplo5}7W<|;(6MGmhp{Uq@m3n}ww zO&;U0LRKYtUTn#y!cG+v0!tn%cS+VYVy))kB_AuhrBxNeuJ!l5-3-gPfDymE+k?nb z@lFO{QJIA$K}Md;wmWN7HKJMpekD4Jh#G=R_~ORj0f1W-?!)WzOW_R@b(2c&Gpz}s zl;#9zOr1@Dmr|YV&^_jBOM)pi!j8QLI&vb-hv3&s!rpJA zCaj&7mXf1!0q2Y1FBpz&TV9mt-@y4*4Ofv zMTu_`!1@9_GKcS=*~YKN>?#Bf5OO?zqL)_N!feVM%+K=|(Epb};>BxsKmE}k)W4Mf z`yc=G`=7ph_OWeimto7T7%Ty%pCAO5!KUP(S1#-K_#o zw%>OT=IRY=Rw9EJ&YL|QuLaIvLgzVV!zz7f2e&XzF?|k^l zXPY5S zK7H&U!xZD~U1IRsWc|>@I-|jFWH?iwY}>v3;3MXat-_&OnxK!SK{zx~&yKl#Z1pdf`zAr9zYZtwp7dYxDNOM%`N0UQ0MT!&LG2 zYhT?RpQqGK|Np!fcHO9^zTty8rS8Rp@LF{9?WjBc4lQ=K8TL2$rT+z)uV!{#f3?RT zU=JNZ{+?vqh2pOXuP`~EZ-G~tkiT!g4S?Um{`}F!7mx1VydM6N^1Si4$895Udn-2g z{55jmfO@$r>5SB2w|_4Wu(O3=*{s_poq>0tad}82uo`$s|C*a)XeH}?u{0>K9 z#RRP}x_N;M$;#WnG=^pLZM?l}bpkbiu#O=KEPq!aZ-sD0J)@WfFa%z^Ml%)VZU+5j z6UqvFz)Os#1i8_TMDUQnEFktuCy<|P<>yS^E&w}t_en^P#dQ65p{R3eWQPU8P-rd$3DqilrTl=gZd)Nb7oFCq5Q}7* zBpMt!^2DB~=jCYl8%Y)PgNacHVDu2(QYMjp={C#|=(zBA3b_^>EL8~}7O=kn*!rA9 zqdh|H#=Y`R2{m+~Z4FOT=5oT`#=P`MaNgVNW=!C*hQBllJZ(;uDpiAyRvh&{#(rV#n<}`8VC!H01;1QaUE7#k z99vlY=EkzWGR#zP0(EU%Sn?AI#vtXD%W0pWzGomGsXnlrd&0y z57($`{Isi$Jp==^Hj;#J{n!|2N9+W@9F%ExJF#JwpVT>f@uKR_N^?B`zE5-7HWFv; z+|jtZn>IfID6z~@0TBdB)HD#@v~EpOM$aW@G~*f*JWsl49y6K+98fnn7GYRprY>B& zec!QXUw!-iPd+!ZBu-td%_>_58)P0E^B2TfeT@2Lu%?UeT>QX}z#lS<@#paO;}4nr z;9cbJOHZSIcWqsFH{&?+m5xuQ_1}@itCsLa<+te1G5BSP4{_be9=~<}MXv~Me&BE7 zZsE3v99RJ-DH5ie{@Q!ijo|Nq#ZB^d2HJ2|n)QVb4{^F*JYvIalkfk=!}tb@c989l zIm~sg1NLRH&DV@99M@n$n;Ef;we=mC`1`!iw~iWX_q;hZ>R{BbvCoIo_b8+OqJQaG zhUvNROUScMUrYG=_FHdXeE;K*FP?ki!7cK4+XH*|7f<(>0FKrjLU51en5V^WWr)T$ zUFA`va2Ive%i$ix5x|OIpMgF6{%a_t-pK4D696YYme11;0o>56PEHt>0=P`jF*}1v z!V#KyJXgS_WfSuCBrM3KpmIh&RMTu+lPvxLkr(){gDzv}I6JON0PI0?wk(M( z=024=#wt%Uf=k0i^h8Cl-_!9o#O2zDl0Az1WLu5DY~>yD7Ip-V{K*}xIynAcqeEhT zuBH=TBho3+zgk{w=cLU*yGFgv-K75KXQ-K1{Km5mf5C6DSN<-+>a%Rap69>(UxnX4 z{pmmc`PZMldUV&ORZABj;|v_46H@H(*an0}jg#mIjIx`#sqRc5g9Ko`y}X}&`~k*i;% zJahcOUXy3foiT+jz64cDUc;R05_lQ<##et~(vG^qMyrob$Q$c;ELXYx`hU{_saSEz zYh#F@VNL($R?c*Ux#Ux>%ofE?z}Z+;SnZdF#A3CU480C5bA4Baw#Z}w?i-JSW9XP# zM_6+Ku8=K4JL~H9R$E^3T1|<@(>Bw;aTz$8dL3eNe{~AK4o`E#Ee*fMKCkl!i9Kdt z4f?D4&8WW#zG?&}=nCq-L;f=j&*7+@@=7y5x@bkQ{ivcsfjz~8%s3!bptjHo{gB)`kaCUHh5Ag zQ2ZTDJd|~=L>wyeSBct$AX`{?#;8`TuZ6D=vo~#!o9?s?zY;hZuL{39a!F?arwepF zei3ErDewqVqO|bi4Wh5?oeL2%@KGx5AlApX>hOAo({zrcVsW%DO>X(*38cZmD@Ps0 zUG;YHSF(XMPC>YN5u|PeO{qSmRT>K#ol~U<80jG~jK)sI7UC8@6AI#@z-cT@D(-y(5=%BWsCjns^Bxn(E zOd)VHGlu{+IdVjOeb^J3?HrrLtX+vuG(rSc7 zen-|SfVu7hvPZ8sf*QD0!iEf&ME2HEsDo`nr4|l-F+#=yS%K`|X1(X3TyHYp-Bmk+ z+nUyzO$e>TBADNy=4TRajJt!dXXDCe%$!ANdE%ZIFIr-syQRwr`KJr;nNR-lKO2Dm z_^^n(3b(@2BR_r3z`ft9E z3Hq*uYqsw@a{BpK-ZX17U3?)gcIA&XGJ{y=KcRrx!1o_fc@=YCYIqo)JZyp^}b#*f1b;9~g=oPW4HSE!(#9q1-;7$xFYM!<(!!7{HM zT5S~3UySWUVSp#erx-)7a5cT{v1 z0U#&{(q+;Gu>pFSH9_Z63sSC&J5l5cU=%Pv1kV^txaQNeSX6o~$}R@REX}y|saL5| zwJKZNTE7;5v&7@MBJp}mS+Ze&^W<;tU|r1b;0d-Wwhz)@+x=JltC_b8G3PXMb1}6? z0OvOPBjoP=7*l$>e4#QYPP&uOtGlMpm_B3n>^ZYFJ}+9bSoSVkzG4NjLTh&(d-wMp zfB*Ey|M}B5&pdM9y5)-r-kn7VG@}vTh9Q+ZXvs}9wu?JJc(}jaH0#n}X}=NfhZoWI zlU9E(zt3nHeL!~>w6!vU z!qg#Z-(A!&dWo^Pkt@q;>+ypmj6QVu=o3ee()srAp#%Go!LWPhHWGMjL?!)^w~ESCJhnS5yT&f7R9pA3y%o3k+WLHnrymAAV%2N%`vg2ZUVF@#wvGb?%vB zp_v?oFe5L#_2%m@KmXM6#~;rc;xFq7+*rx%r^24Pmh$! z9dvU%Lq{^g^gPVpp>2jI`%OlCFk3X9rYXX7sOr~cqTh#0y3-v@*Wuam7yRmdGV#@v z8IIDm%ETMyeQwt0Crvy_QnQy{dWkgO?@qk96^gudVEHIPTfCaZqlBJ6z~ ze|?6k?2ygnA65e!TG2#s)4OyzVlbodQ~*ogyz2qBlmgCV>Do-X{RR=uG9VlN>fe>M zTA-te#j@Hs%OS6x;N{D(!%-GdF)fD;jU6tCZ_$z+-XyFDCZ8XO>^EXm7TC}4t5RmBZ zOo)0aoCklwN@3Uq9EIE!zX2jfLT$UAG-YrdIMNo@Q~;@VyOlsJ zMqIz5L=@lTSB3Htjupv@gmoVHjv-LZ47u0Sk+t|caRSn1bh2)SzqDpB+{dVoL4d}R zMN(StBfHW#@i-cv8h}B7{O#H}z`>&F)D}h>KwPH|v$9xoDyrDg5`#E&u3|YolsGke z_+XVy3Xi7sgkoT8T`Pn6mnE50{W72Gm-paU+dcPq;7y$j{bm_gHckN4j%cA3yZS?rob^E}S)O;#k8Le%J=}4NEH!(q?Hr8?;XI)A096adAC5 zt=Z*=xbYo-s6C zjhwBC#^20^)%kSRb+l_=;M<5psTmKco!8Lh(1w{DtQu^7={9vX9fb?EgRkt4qC5WX z5ILrA5&8VxD@y&|O5%;F`hHvD4S$Z0B=LqFf1f4q2Hbu1<(C*@Fq zgOV^$ta{@VdrX;Z(7RlC&iqm3Qw(u<7 zqQkF^1mR1C8tDZx*!&bhvi`W4V_5p^tU{5i+T>)FNAHrZXFyk)h|0VKj87>%m$FE(p?w&_p`dJr%^`}4m+iyO6?w}4} z1n`_$WLRzhE@7Q}cf-xN3-WVr(Y<9Y@D9`uNC2aMy`-@WXf@{wUY%>L`Pr;y^gNn1 zXCVy%9?kWnDlq*d1I?JO4zZRr%3$B-^nLWJaOdc;X?-*!VnP+gNewhsAy6!&mgbM=v$D$K$7cy1ppp1dFH}Z zo3`zKI(}&X z-UqgCS-WgL;+N2oqA$0v6R%-u)3)AVshivGj1Nz#U4hGA3w|#CHVsS~(pHAK)A6O) zR*Z4I%WIv>hCeYp9Y)vM!d0L&0<>XjF>7ct#^ze;YyXL!z_qT9XXthK%iHvTtZ5x| zEFQUKoq3iyIdWw`7hAJ)`9=<5=$pSjnbrAh>-c-sHRNY4{4yj69e>SxwfiB|?;-MT zoHFv6+y272S6(}xfhPL^Xog#`p%(G`E5w<{fgyN#rGUwkTB%$44k&L_-+@(}UQ`hf{a#6r}3y_$|vY`zXkuZ}zZ z8vLBHr2riJbBEN%U_mT@;b#M{(Ctjn8l_7e$H0ufUAb~)i*IJy3^^0Z!>r8=F1|xB=&#J2YfUXe@%;Nw zUT5RzCK8s$ChRH^8?1`nL8+y@ir*R&*qLIr6>@}7#L#!klHg73^)Dg_0aXTQq-I)c z?NDe8a2jfL$%tLpz;Jtv8(}t`^Rs@- zp69;!m;cuZ;Q#ZxPhLFoz^0Xp7qZ>F`SWJo1%MN;;LqP5uFVecO9;O|Z!SQ7P5ffw zO5mZ$?<=yH%jo6yvWs7ThcW5gK01jv5F3SG%+Fi4?%1`PWCx4~jDAHVI1YnGXopy1 z%`Sv5GYOE^SN8Zp49|xT**66Io;rQ{%&C*7P7B~uAo%z(Y|)QX&tb{l^B^J`25(5; zAY#hMv4oy#0=;a~7{$f6opELVVn=CZ|rFdFtt>&zyPs>8HuKAa5yW z&p!Li(@&i_b>jH(6DV!ojvqaEVE?`c@4t7$s-^R1PED6Nn#ROed+TgBwXv6MLwQ5B zN_Edly*K)@xgT+xy6d_1?Zw=ahGAVop8;E)D##RpLYCo|%Tj9yO9j%%*Pf@tY#lH+ z+Z17kUI%y{`uJe~ITU7x52>5(PU_FFwcGSk3EwZz#PIIxyEH-%4x*+;e&#R#GNI4L zUft-RgA514phqjryOGeVM-Lq2=a7y^_h{I>8~|tF$xq&V z>e2fee=+6^tj7VV`j;Ybu|1pi3JY|FU}Z(=-`e6a{lU%l>>K>;^{;85yCofcjhf(b z>2hHi?~Jt>2TthQFx(rb^$%-*w!mLs%r_U(mZ>=+c!TlKL}O`|4u2zkWv`xIff_lS zRFmcDg|Of@pcS|z*+^ND{zjoNNEW|AFRrlQ7yd4oF^K>Qyl2giCP8%S;=`rbiG~`8 z`bLUaK?46+=upTl~tAg?07O2 z7$A=PE&f85tFFBfzcAO78k4wh`3tMP65wV0_;GiTR2TeuOWbk0n({S56bgsG98bW@ z1b`bL$XfWX%v)@)s<76>Y$7;~2^$KzqOm>`kOqJGF^-*d z*PLbRx8DEI-hF!?*tTKSk~uSG%)kju?_VVFlI1)LJ}m1tY}x(PC;zj<@1Oqjcb}d+ zvU|&_Wyoff@YHdw~Ty#saRrm)I+r z7%}xPN$%;7?AQydR# zIils6&Y7oS=4ph=Q)kXFee&c9sC?|m(I*bG;bV_H{1DkZwr#E6x%R5M-S`3kOceB0 z*WGmc9aCm4u&F}5>sag2DC8uff>dE2KFp4eJps|#mu-VbA0f_5uJ71(4ob?k zUT$~UuvmOK{*G(|w9x0P2z|c!cJNCu{=%gr@N3#h^KR(;O}AeRB5yFr@A-^5*s^XQ zf6M!e0oo4YpZ(;MH=o{r--gXJDR)d=Le%F%)CnTJFPT>MSsBD@v96eAa#8%NtTR%f(thu((Yz7KFo-2gbUwsl6@ zyt!hdK`_+@$c-ykp^Gs&vR2!2q1f0fvFsA9(TTQNp$2yIAX!mNFJK@Hh?g#=x>>kr zG4WTljs;~HOqG+6szPA2Y{aW#E0V*uK9EFjB*Y30mp(>Pmn)|21-Ez zsKBDG@4*`lEG=R&hAW|e&)>?`VfP~|?Vi6uE%kULaT?J@WE3E2pQ-nXc&a0!n}fZo zBTM;0+(0*T-BfgWs1yRBDm%R7i<;@V8uT56Ielgm^>0qG@e}DOOvFq1fFo9+B-c}Y z3*aaob*?Jcmd|Pva8F#@Oh4rqXuV_*Xe(ATPsvs~g< zc8p?gWN^@%H6d@%+xRPdC9rKJ@2Dl+wymnEn-x*~M?jGvPyUv#*Q4f`)Rj3#FCiCH zx4Lfov{6P+K-I0@y8FP<6Q@oQAawtx6^n=iCI<&z*ZB(_lm!(^ZYVNnd6qpexN4BV-4V;Fju25Wt9zPoQ((oXP7 zdMWGOAGL%g{RW+qO>{u8%Q6mQ-Nw!L+`BF5H|R{XAGfZWApj<_gsNrF-s2}7kT;&Dis8iC;!YT%ahF|eE7hl52K@Z+=C@xF_M1LxKYwFkJ0yN zE8ch;p7I&99deF5m~_UdxKYy=P;c!bwGee16&!V&wHU$J+ZY}ZMZIeI;stYNOr13D z_M4E@S5{J-?|cV>8aM?od~q_jkUOftZ7R3eTPt1PK9tG4c;hYXhBAU%13A}Ql38Se z=Z?lBHm{l5$Iz~7TO+TeW{}wdv?HmTbhxeep#}XXYU?&Tc=H4KbbV2K&A|*Eg(sJ@ zYwwxw7F^~ux<&4;o38f;-db^4{8MjEh$W5-x06!R}1tA{Xg-;;o{AndnH2Xb5A< z#*J!V>1srkY^Btz6Gi2$35vUIAat=;{I(*1Da$DYKrfQNi{{VJ{#?{-=!~PQA<#ZA zF~WtvatoRO;4(f_9}&Ad1}CNzMi{7ip|ALLBDI$SI(kjlr**#LphyT!iA)6(rCGIm z_xR5)gc%(uen7=Bus=sXMMtIjrs~d!gI4T>>>%=}^kTM+hEE6=b+uZhjz1^CCbR}9 zoRG(*Q8p&of)qz4TEdD@qF#DxG($A_#UDv6TUGD&I^< ztO>%#P#F1_Tvzyi)xX!@96!1l{G<+hwyA^p6aHeuB)I~%>D2y);sQb|eDzj3NCk?y zy5iUC%mwBWdzl+z!&v&yXlHMnEof+Srs&5EKeB_`p#(PQDXjszi}STCQr6}Q6-+h7 z6O5(u^-idMuW*|tf;B~ZIRk22E=+bJ_-|}P#fqs862WDFrZpvSRhHFs@VL?86s-yT zvTTWPRQSlp-Z^8zij6xSJ@NDlFTZ^5?5QLBc5Ym;n1T9;!~(%7RP2f_E> zw|V{QWsBxcXLRFRZn&lZd<7#SkuRIvM-!(wI0e>u!o&4T(K&+J0yjA$FLkjf@qw*k zFwL{*ov^{#c`Z2a{uQlzdBZe<9ta;I?H+FaSh-DrUJtm9ag^ZCukYwZ?UE)R8R2ipaYh44KQV;!B;KmWD&J?=c;cg-Da+KH$BCNSM+Uy zV6Q)*!2~Dfj2EDl!MbkBO*s3Za>?H6bbaMm+DvWTtzoX4bWe%BBGbaPs9&-^C-!QP z2xgyS{vNN6M}|JXT>3ZU6~0DZse9x89XNpBeGmQn>D$j9*baa1-SJ@bZ=efxqg4x> zA{hP(;AVX;2XHTbM-aHU>u!dFpEKX&umA?XX(XD7G5`*3cNhsx_PEN0r5-l;nTY3D zoI_tpyrqhmg|W^0ytd5E{Qfs6iY=g-zV(XOqHNQ<4Z#4pM{^Hj5zS&t4`Ft&GB#-G zYc&IYDRZaOG^YD}p^Dd{?~pGy_*A@6(LoO?yQY5)AR0G*{J467zlqUphGX7>?q~=g z8u3^5QjMX|LGD&j)x>73r!B%-`rFw?qj)+nrs1A|CpoD7(vl<&omV(iroz_o=4b+F zjucKVM^gHe_CthxD$fSs;5RT5M0{R7*-}2J)UxN&YI4KB97=k0B$kj0)-Op@LleE1 z$W}+brDSjLAO0$e2!JO4^L(sxoJD~|pu zmzTQ%_GusCp0~+REvD-GMq|zFEZoxTZ@g9cyL9b+dyhVS?);l?zkT7gb59-J@4yOk zX3oG1Jck?u%kL)s8UAj%_u;cY`Cpv__+Nkh$@7OE*s_LE{T4GMCr#6Zb7oAQ=s*lN z@`JQ*_)UpPC=WcH!$=M4nA9!ys^Pa9af!k5Qszq1Xy^c(Y-c38p9|z2<{bTN_UDHP zzoJLc<46PQre=etolmEvN0h#JQv9iBUf1kWZaA4_PyjbiU*4`0wJI4K=fm}}X*hso z5_i(xvt4HLQq-&C96E%rPul)y7sKl|w1IOu<)LN6ll2w-DS7^V8Cu7(?qImcr0`TTq(eeU>s{=6N36Zjnb()*Y44)M7rH?M+X~i#q3at3A$LD*IxXps1?V4ft`@#Z!1`8 zn!UN4y=HH1{wC`QzA zLKqWj$6tY`Vhi@PD8nT+bog!UZmpjZ{0ht==P#cGn;s4T7QgmhG{CouJ}x1ex;su- z5NaT4-&whKk(vd?^g1!%XqF)RH8jPFB7N;4!24GyM7XTg>f1*W7Cy$JW%FfQ1Fc zUv5ptt{Xq`&MBt2A4h_FQfO1zOJB2YspB~dAS`-g&X>n^CIGZ#aKI{N(Xv{ig)|?R zxdBEv?0m3}XcoPq6reK2ZsP(b0ITD#*T@q7M)Ved`B=Igfn7y#!MN>;jq{(2S&bRu zcesg^&QO_J_^;t_*)sxN!Am@GGr!z=yT7no^-mCbjJe^~(G#c7U$J5PBgdaTcm6Fb zV;A4K@XGT~9@w>cssxfA~y)ChX zXY4`R=j7IS(C}v+uhRE1;;^h+Sdtp5%+4s^W5;m%8U%F`PjBE`prxjK?z!imfBv~D zXQ?`$r}BK^g%_S@a9%>Ejvn0q@a`R3D_)A9&5edK8ZV`F|9kujxSu>J{Jb!_@C5tB zjB%8RiIeV}I(6!_=_xbd?$oJMCf^zFhYko@hIVM`M>zx{vR0P#{B=U0vdlFU@Djx2 zMOY|u#iXSpa5!EY_dKZyIO2pj>Gj@->9#$JIp5@7+oF2&lPR5a9i}JKJ%?L1=iwzC zYa3%TE4!T^`dnLGax@3ap@ zv7np!P0u5KiEB4(xi4uqD)j11hWm~9eWjw}U$=CYXC1#X*!U{|>|Jycv<%IUzB&SDHvCl_w`CH%Iebe*vo}ARCqo9eU4!5~DF!Xt zWuSF73VY-3Y_2zx1(4<{NSxBRHLHJAc5AO!0XbeRu8lcOE3P`HPp|;aXocvAc zJu}X67JB)sa)rP7xEAPGwUvh8TR=b={-b~che+W71Qi3TGxCwTRsQBvbe*8$wvIQT za)3cNT+-LdBv3|G*=1D0L_iK9FJ;~x<0!wk;Zd#Tggo@G_-nOJy$%&~WHt+I708`% zr4d)5CUDDoT5J5SA6||0;$Yz~F*$*4@S7$FXPmF;E}NjYZ!HI?Lcdu6j~>ln0otF9 z^5)81eXT>sbM?y03V-dYOe}CYG)thQ#@IlcN~86SO2F) zVEx-~hm%Ms&v6J)j zYxV^13#FNi;sVy^I&a}p`u}decU!YRi`oMR$ofZW0xZzfEmlUR**Hiv>QMusjuC>4 z@+ICGw=ZU9`i3BLpJQ+ux&;Z`=U%XX5PvVeltR)3D17$mQ^yV;cmyN#rZvkJklTyF zooLhnV6Su{+`gw@qFQh5>c+Yykzw&T&zANEPLJ_4v&W9+p|k@y4dOV2xM|I>tZ)^v z!X!o77I$S~EiVwjh7KFUd~6$cZ|tPoYUq8y6&Jdr!IHsl`wz68v|SBt+B37`W!_5~ zXI(RPyEwxXHpDt#lYc=OaJO65Ig{P4wGn*p52z;U3gzJ1l^HtQp_SouyT}3V^5NHBO@MRdv?U51U;uqnhswIZ%Om+iKE3$D;rlm5{}M152MQjPONt1Up%j{$7HL}eby1wd{OAq&3x6wyixz2i6auqV z+NQQsD=@n7i#593z#V|KILlvTaPgM~mMoOJT|xii>TQ8m#o4d%H=g100&7IZM-!=w zts0rDQ&)M*;$S)S?N>nObUf1cW!}j`FUBSCYu8BhFJZU^;EuvW{Jk|4RKbFkGN)S8 z)1I#;Gx*T^JIr4`f)yL_S~l&dYJIQ+{5Hm=dWUrqKs%k8f*?0LCdQQH&)`@6oBVmy z+BCM~bX5qa|B=0qQfX69H#S~DeG*DgM`KwVPcgw16}3b!s_W}k+Sr^(rLJ;G#~YJX z1X%L7Kp`B8y&*i`3w3Ixu1V>5`)CId2EP<`3EBzEC1^HTIO;11c@`ceks^=)rWlF( zO~rQObs1Da{wCgvOb=9*SbVR$!3)B{^XiC&Y7%PF(I)Mt$q?E$Bd3?x&?x|)G+YjW zlWVPzjT<;8Sj3H;xyj$?-m*Wl!+gZIYKM5X(Z2?kr;&91HJz{7HI1dwv^C2zKjDS) zv%#=bMj9)9o4H!~RM)m%b1OsNs>|^j_5hY)tzdd4&&D0$Agw+J578%b!)Yx^AWEv3Qh-z@qEYl!?T-;r&h4R6GB2^=T=|UkuRYg131kgY!z;ry6qV-yk?Q z+Hf}84!PaLVCi&Q9H-m1ouq%Jjc;X?tUv~(ST~`Ct%ZnFIfCl7^H15GPhoc^F+z;Z zn3++zFP>`vJ|~A?eEB7VX2_Uf?fD9si=KP>^pm)O_w2fFGXS0~fazv_<@YfghnBg* z-~DbHM+qA6_u&KX z6pdmSG9xDweRt3T(fB|qz#eoI7l3~T- zT-lGx0wObT=*VB`G*l8wMbp29W@$neFIC@Yv{I58D#XJ% z219B@VAISbiGXpjB!g0l_Eap%k-ygPN=zY_zX&jWqA`WlZh57ttpyjzkl@K`o)F~H zpw!z@Tf+g-kx^x?RQ%Dumhs-KrER%WPmfWl_adDpf|)(6IH_quVH7Z;JZ*x;4X_Z@ z7k@kUH?E)tb%vsSM=P&$tO6K$7K6K!?3t=p=~kDG(^qm{rR1hUzR^lOQP4?0Nv|Gx z3pweof(_vY;#DyaUVkIknJefYTTfza!n@K#^`=BjTiMfk00Op<(7(W!C3c2#P7`x3 zxBQK)=fxI}l$EedDc3ZZYIm;XY{RqF@c@u-Wg`b)mA{8-pP}HzX*|QeL=F zA+Ux7A?$o^qn~hd3U@8NkZeg|gQhxXtUL>KIj>yv+)}xp0_x}iW!Cs9lP5Ds1t0_{ zIscnR-#Kf^>dia$Ja(7}tn=@F_T}Gw_0>=R_Op*JJbz;Uj*WLOq7%~Mo1$yoyCQ>qQv&-7pwAfxPSEMR#mnzrOV1zETaiYON+rEAbcRv&APVdQM6C0X zBgdY^;R|+8pE`Z&)KgELQu^xc#pq1;keAMZTV7s#;iXq!vetY>(ZblQWX?EG`iz%= z^K)dYI=p|+u5FuFFI_Nu`lPY6R~W_VZ%A_zKBlQtVmLI7D@W5bzXqQp8iO{qW9hd7 zNS^DsgJ|+{zjCwceg(hXZU=_t0Rh@nL5-RJ7JLq`@3>Ti8eWr)g>CVSiR_@GO_44_ zvli87*`E^~zv@%&#r^a}3U^D|Zbz(ZGXZap--h8vVJy)j)o^C{V0K*xGxXY7p_ zSr4uMGm|;-tmlv~*{&_&tuNgc+V{yj8E@Hb{tE30w_;5n`h4K<6DR2RtM&P%XkW)W zI)DE4W_qq6kHBx2^-A&E;-BCB;L|U^`0$luyEifX;LhFZUiquv*L>xTp}eVdDf?Ry z!mV^m)WjCK-2A*9eA#RG+cxM|3*e%CS)lFqJBWBrucM&1L~x73%GgInKUdKe41aq7 zuPgjE04D~kXS04@cuN7aRajux-sNU?jw!m4d1Y~#RTNiBYJ(W<=(s@q5@rE^Cy@TI zC`r9vMF|_rb6Jlo5~^yPs&fzqI6YHBhK|1J#e~1?CiqN!HP#~aioZk*MO_KFl<-#o zSi@4;u~V2{4S|GSW9)*9J%0nis9$Z(RQjb#g|Br#^?ix7AEQdKo~0;)#~LFBh>`jn zjQhuO$+1ewregda4C7%GvaM+~fe$NqYd&Vb*F!hi)eS&CO_xY@{J&~mLxW;$2N>5< zU8U}=hKt7G()uohvtFZd9u?U(Oi?6%UGCwrggh6>WDJ+w9eOEw;Ers2=bdo@BY+c- zgwfNzRU~lL{OVy(%#;x9GiO!w<;dZ07|g3B0Op&;Z!SOsGn?5w5}K62lxr*KwUoQY ztK{$1_U5$@$>0E35Ll&~2^z;C?%?luwKX*46m?KAZev*i zX3W44f5#|-!E|3>fgV3~?$R||cI?@I_{1|WU!Yd_+0TFZ%U}HLi}x?QaCGl|YnLxt zum}e*zMb{!H|%`!z27(c^S}J+qZbZ8c<*}LGb`7uS-Eu4{8>b7&6uJCn8p-+*ltSd zjf5L=v+gkd+2&De5-5PRL(_`Wx!;QD?fL8d5Wu&N8b5)-&gUN}%nzv2HHFp7uaKz-_`ZJr!W*eN zFTDQh%jW>_nJ16zf9QejD&RRLjJ)wWl2LxA^VX*Fhni{f#Q5uVC;9gG%+a6Uk&TeF zzO`T_$7UWp?wIlyGeutcm}Q8*o?#9 z0ey!FydOE+(U^C&ZC5ZsH-%d}62G1PWt-vE24d}L_UA6?#*V~5OW)#dg+fOaH~o80 z`X3d7S(IK#0C?@%&ifk$Oii&N0noa2qkuImhrhtoB7zgv+y*#GEY_MeWt#2)j0C1+ z3*$QhFufe-%{46nDbyLVdo(2qHbhnWM)*P!gFk~`#i;5o{I$BbU7Q#gEzGu%`IshS zlrL^$63#=s5}+B46!9E`=|E!2f+#TY>yvI}XYf$~nLbfC_kc|Cw`6F58!s$$pz607 z-r-lRluCnMs)@~x*NVfiz&Ywp%+X`UV2`G7@SLY1UYr!wr><#8C0r>AI`AMN8sk&n zBqXQ;k#5igk0{mm>v9$0NB^;kL8puMNYo}!psr93%uV6o4sJ4~*JynaoK+Q|9 z1oo^6f)1ydPsXo`yt*=dd;?7yA=>scqJUWEGRa@LtW7z8yf{gB;L^H*t-?2y4usu2 zg$=c0@LHD_0Dn7CSm~}(6*)CKx7M4gi_+_53k|0^T_?!oIA`|E=~E|-zVTW^ow&}i zKrdgrWyjvfj-Gz*mABvj?C*d6>)-wN-~RHeFF$zY^y3d~U28)WjmyKa_TEDmepv?S zKmOA%J|zD6o(-#PyRKNqC=3KkFPJ}T(pb{cK+%;Z1asHflZf-2*It3%|0r z@i+J#0&ufG2LMC-=m6HgH);&FE97L}mu|h_34DaM{LFml#%ypijJp2wHPNO`VwAe#S z$x5bbcbRZGv%dAER#%hi2gHif@z&Fk-mJZvj^8 zbGM^zOSYoK{#>j4KJc4P!1e>KFlYe0t*5U!p#x&y(ZE|;)D@oJrh-`#7w}s2E%X$( zt!Q~}7HM-~mBD!>+y%bAsfO_Y-z{Bz&9c>$Y@lH}B@);flRrlR17P?|9yxmyh~KbR zyKnGY*rnYoT5SLJ{1qB?;F=W`lrL zRruSG9&2m%>zLgfeD^M&$@inS32M;ky%C-X6OC_CVhy3kuPGt-ok@X4o zx=v^Xf+l%PKWam!h!WFCpsO+b2ZY$4vu^`k4AZ)aZ?UDPKa97Vm*k94`6`ns+#VYslr%;{Q8~$}XH46i zm;f$WTRa{4I^eH{=PKD={)WH&eJ2(ym^WwU zonvnzOBk2=Y8>UGCQM(jeBIVv4?lkF%nPr-{o$8C`{nQc`yYP)yI=kEleeBf_Q;OS zYZ)168IQ<{73=rC^0R-70RH12zPfn!;Dh&WSe-FCmtz`Qw0!N_l?$hiPhJ}B&s=nW z>sop&x0!y!hA2%+?=L9!nMiXB=;k)GmlDJ*;#P8}ZjAUK>E8;+AEfHrODCfP2NG;` z=*SV1Y#ce7n5!pGl81=CyjTQD2uXx9U5pgJFTN1rOJ-)7OM$ZI&trA2f@Z-{#~?Lt zU2p+L=og-Q=Jbi92OfT4TLbWzTYiiM`ii8?sOr8|^i@^=<+sqV1>ky`(o}5iNewvM zc^?m*LENs+1pRF}>?a2bSpD1f*}Z{Jn$)UmieHaL>*hz9RHUPqky z@Y0djk;9_o^OsKa^Mk!J72ogof?s}slW4t?cGA%2HsbH&hfP8n>vPk;>2Ty&N9E(q zn`xgB!ohC=n4z-hfJFS&=O4cMvMDs(pz%XA#ZUjbhb+($t-@w*NFI%!@?_}kR(M#ne;z!eG|ByUWr z4dK}$nIUh-Vc${5+Mla5{vv)YB(^Hj2Ea4Nk>Knjzrqxqz2W|7N_A_4r!1S84iJ z4<^-98)?8}F`|hAf9>X<2VSXEl{Kt|zdyJt{gSK+T+Fg4B?KXjJX9i-Rqvv~#jgc5 zUV?m_0H(!ZDnX6Vu#8%KaB%FZEqx(8vAmC#!@Hlhks^4m&D0OXWlmiex zHt~zXR9@23C@TVj4*zlZi=GO9QK3Xmu`8|cX5=tYocSodBuHSo9Z@igCIJ?JR~1_F zorYdXcd)OVrOIy>P*^~tfkin2QQMVxeO-#g|WE^U24X4`P`^6FR^@V6Jix+5ciQT3cm+8wv(|K)mLea-c^jALYh6`Qs*vH&jN*WUj4?|$~{-~R4@{NaE6=BHo0`^r;? z_H5s@dKr%Z&%&w)p8d(cqzBR;|M9Df&m7zhf0r+%rMh(Sk`*9)=a#!?-Z2U{O5(3> ztEQ&yE$)K&ZBKzsAD@ccWA1w{KJ5X;Zwl^UCIe-!8y<_X6DLon_FJU^y7VuNemuTr zc0PLO5PgjZx;l28krmXwa94vf!BvJ@y+9$p+2EL0p>Ja@LN}$Hb#E}LAQr>7-+mK2 z^lNY$0H10;;5AE097$j|Lv7&#E>e!H+O4*!_&dvk)|xm_{E=~X{IJsS;>O{q|2EcV z|N7hIWP`8{M>`xvUiXr$A?&{@4MCMJStK?D%Acc@>#`j$1N;W)F6ofkHuFSkpH5L~ z#trku%yzr!4r(A*YiDh_JN7gA7|UuhuYd6u|K-2@7r;As&kQfDuGhAc`t~}KOJ4=; zh?Yt}J96>R=W_IQ!MaQK&EHVI-z&cVLwZUgj2MQxtk3j3A_E%(P#-vSG@(~#iGB9R z#Sd#Fe;b4cc_%eMgJ4FgbhOG(KL7l~*G}$*zuQ#P#ovJhE_8P6t#`-_XF$E6O|0wa#WaY#D zJVpIW1)pNrF-Z+ngc29r3Y8R=I0FD;h?cd`7SUTaI>~?#PNKa#r`|OqW1r8RGjrNx z#{oyK#rrududL%KokvvvZ%n%2Mx!ppUascUmA_WjswUp}3uoO5VO8fyYtC5;b)@vfRLIlnfO(ab6v8!e59G@^<`XmTygm+%Pe{rZpDe3S<}_ z8Vg)0brAd`5uwK27L2V>RrofZEH2 z*gaKU+B2cAR&3zwB5QpO3B>?N%rwhnQvksC7lLDt=FlkGyIt&E@Ng-yO9#6STnID$ z3o_v?*OyORb3Oe(wMkf1v=%Q_ZcN>yGC8}AAMer2w%_|cTh!J`Tq%O9WmQH7^e@#o zCGQ9hr)^ElEZ2l|8Ur_hL-=oJ4Gqm6_dKwXSb;e*TjLigA8Da%^jc9)Hob0uJq&QlU z73J&a-$3ua@y45PU4Xlal#3VNmcWb`h@txV=bn1jGHS1z72ee!t53}isy z?_L(b*8O@5`|FNwZ^hUv+Nj)5n@nn7#BaMxrF{Jud*$Y7#@3tMaixG!FoI^Ct+r#D zSSx@IL1yG+?LmHaQ|+D4j$9&Z{VYpI?!qM$zRKOCWWG)N*5=#SwDy4?sWO7TL2L)y z!f-b?QWUrSy6;O4sGH4I?^{C7)tc_T+iviF$odcE+->ZY zV;<1~{qe&Lgynd@{JaPw;MWx+%22#>e7>#A5#Y7kF94Rmln>$WN9RvHymiagZ6sd@ zzdC>&tw`1elwoC?@h#H0)^`97d!cIzh;2o5#={ajz*H)bTl2P~z2wLhnH z0G7WoKbwdn{$Av7GeDaS3;Q!=<3^pp0vIcFin_N-EYYQZ1@x*of`i%>L^%UqRW5)v ziNNv#vdap+pm|Agm#j96!ruiZxtYswYvad`8EudhMLj4+1{F)eHx-V77+|-=u~U?e zzJQsEO6i+%*5=M%$d}N?$j6(a;hSe=%YHK0HsW# z?3xJNq6=TaAPZ<;t;4oexK`EpNSG{_qVQ|4+<_aJ)1%@=nX-QhQY~Iz=mYErwY)_2ov)oAAmF zl)%2=<<;dIQ)$`?E^7j~-ZfKq^4A)-NLmew>#rwOrcCuxiC_MtsCS}kB(W?PG8_4l zl4X9vA(MUKGX`H71pS?FH}S(v*@t!&{ppr1xNH2aG!lUy zt&tz!JbL0?bC;~U?}5FHZu{J;Z(aQS@BiT!zy8f{fAhOv{o?6lIjTY~tu z+w!AHJ4@nr`1Oeazcz}v$31q3CpbX1zlrG6DKq9RS-B1eFrhCbx-ug@`j?Sso*>JW zaaX#2Pd}r%`K6c7*{R5Z08u6yonO(hd;a_zZ@)<;`PN&gToC*w;C<`D1#E+Fy?v1` zAr~*c1BKs&%&)yd-=wo=P98t_=$`wxu3x!m&NKwDnJB*tD5>Tzt>UfxB`Cwh+U~)i zQmwo+BIU1lp8Hnrf{wr5vj*d8I(3HV9xAe+s5iiwP?LJTBp=lXgmlN2h57hk4~?H~ zpAE|HD&N6kNR?N&2(|L+Totz+S-LeHnzO5RfZ4JT+%+9||BJu4gt~2APvK0|Np^eB zv0UzD_&y9z$AaJodMMYY+2LR}HRE^m%bcP3!N1~O+IfMeryKJ3?$x9~jq~@B{S5g_ z@Kq9TsD94}zs6iuqGycI74;nIM)k(*TmVM@hQDu|dE{RC%ZS$EH~f{3@VCJh8W)Sh zQ<2&_C#hnidmDU7PpSJix|r9Zbp>C!nPBdMv)G|~#{+C0=-s<{sf6W*K&O-fE)+L2 zG@XD$-~bl_cm0s$Z#UwRxivZhgWT33Ni_EWhQH0>i=i2}u4M^eHJR(u%m&Fzl0pvX zg5O47#BcO36;AluVv?Y*c^{;2*W}f-W(j_cxe~u>;Lsy9wqg>=W`w4HOr!6D#oGDo z%0VWflE2ZH(l?}(bv)k`0St8_3#s1ZFMO<^Y1E!0mkIzyQ}LH+cVUH2Jut*ycXhR4 zrh0!tFXC6_J7L0vOd^Pty`wN8+P(M|XQA+-tboera3m2XX1a@ zffD_8tKzu4b4Ai@VP|I1faKW~pHodO27 zf1XM5yk_Q^k}-*ysEHy)K#GX;CcQ}!kRmA77<(@?6|5*0taMNi3#ifbIy0I1AAaxm zXYF(E#hA?V%x}Z@+;dO6=bm%Ve(%p(Yp?AwDBc)|oU?Swl?aNPAJ~=+SD%t(4Ic6$ zLgLyDD9EzXyA%BST25ZUob~RTMc%r+i4D4N&6Jx+sc{%mlOwLE#w{qS*d6laxVOVc zjhirKI?*GfvRZk~(giaoUQRpcQoZ5$$}hWo!j##IS8uxc&ifzVx#y+V4jy~|^oO6E z{rsn&fAQs~?;m*W*(dJ3dE=U;b7#(3`@q{Z1k%6#^5iSK9=d(wiup5U%w4+XhC3hL zg%NJo-5cj$c^OSA?=AKq4L>wCjW`6x^@Q-0-c|!Ka=)8>75^W^btlDtj@mVxZ3$N!uJIY&3pF}Va1DJwEnBWzwfO33r1ly@3^X3# zfA~MGx<03F4}V(#md!_s3{D%hT9%BuV0)?bZ#9ylhI8+FlemI={N{@(P z{>ons%kxr%utn&`+{|)kYd-j$t^GOukHDRhGtSI-wrt0zz9n_D=o4PwiJjqOIrwjG%rFx^|&}d5t=O_e? zzt->6-et^ewR)?#sSLu%8hQciGkuRBZ+yRae6>SUVsnOesX}dLP;F{4q?)8wv0Xrk zaXUzlCiBRAa8e&rdq(??j5v?6V7S3o1f406Y`2JCjk$FwkJo)szo+1XsL3zMNnl@R zYH>taQd)3rzVqF9m+5jOlI?!Pw^98X{KM-IJKs{RTeA~<6=kCDk2klq*GY4PB(d+E7G&a%inyLM7Mbkovpwd;yN~{8{|!L5JbBK zyUvTyP1}aNh-m(Y*GwaxapRW{m}=cftnw;auah7G;SJFUdn0`F$|;Q7<6yq4S1n&W zZ^p#2iC=RR2Gh!4Iqm8tYp%cf&WE-=`P@ry96WaF!;gr<`Vu4bnbRlUeRa>{_uh8> znx)G&KmKm%-`{_Ea{r!3@49jAqFJ+-ZTRt{PrZnYeD&#jH_o3hB5kT4a%XYy(!TVb z)AK0&^|w<-A=Z_ThTBk=+b73Mn+A@a;G(dLje#CDo^xEd?ArC4$-hCeEA=n=ogaPl zv8H~XAo7Z6D>@l9C+|y?eK9vHc3-Djgs&=GW$)|GzbSZAA-+vbX?=+fM*m`grW^3? zCwK06?18&~e3KUF*;6Kr9!lRf(qN&01rF#`At#sSMvPPp&*R`(lh+@t+ zHRG(u>FwWbT1U#%t=sxOb6wPJ6R@9Sb#92|<(rmoRH?adHgQ~EuN|YE!Z{cGFTCln zJD_}f1n!+CGk;r(vk zb3z15+{_ANjn4-T9z1{t_@DzIJ$d)_1N=qa%HcSH`H z4Q&B#bw+Bk_nK0~O5+%xbpXR(EYOt2iELKjV)vzlznY%=#1+78Z41AeeYHt(#+E9y zf;Sq;+MLJD7JKUVLa@^gz+teRL0Z8uXDX*Lar@39&CsHyx~P{eUU2nH242DXZ08#B z^5-S|RTkR$C?Te!h+L-Vlg8h9F&Khp+L^7{Q=L-*P-iQfsHa&WBqd#}&&Ecf!@+L( zec>(#8$DV(i)d!`Fn8uKANw(6(W3ERqLIoi%sCQj^53S#{0gxdaf7y?i)VAIJGH!b>IsU`7G{@%@kPeD3A_ z2acaS{qd(?{PfE&zxa}_NXOrPY0r*_?z-jX`<{F6*X95H+39!pKKaO9Th}aJzWJVA z``$cw^vIz%_T0B&?u5(yr9|V>HpK2RYLu-)9sXK{xU?}0`C}?GQKF!2()r{t@zO>$ z3Sjz@c{>=tV#F9kI)m?00aE|b<5%ym_r^}kJ|m~Xq)*vyN$>T~Z%uDi*N*T@v_rL--urIb zzfamLjL+%(HnEL4D1Nu%{V?__#%Ck1=+74YtNd*im9neAUW+kT{;sj(n{>i zid>4`C+hOl*ilE~*BV-9RV3cC6 zs{EB@jOSng^ia;yMR>D+G!#3xpTI67OnC)bLrcxi*5_DAFsBmhKuAT`@`gKu8?`nM4n{vtscdO-bK@y}i|3g58((RRs#z_y5+E!x#c z(}``phdO}=nmdVsPMgYV{Ga}**c<)J?Ik6Xwt-=z$4{C*bM6wX&)2R6z{?iRF~nem z{jq+;EgCiEimRs0S-f)X=3DQ4XvdztZyY^->cdYy|LpTGzx??ZU;OmU2S?uC|MIg> zJ-zqfncr3aqhFmlw*RGPwm*3L4YxeF`;B8KKlifGYW)BWha2OdWL(&Oj} zBCj4xzayN#&r%<%f8j3udCfqy?^TG4H4yr~{Wco+Eqi}Z6T(~m-hB7nx88pDz=1>W zy6~;H-q8O13Q0I#cpeY%t|v?deG6$g7CPk0aJo%@Cl+Y6Y5nij*wMd+`|BX8mKioG z|I-ror@(CsZQ*ORlzeAXIOwfbF>l4O3b@}92|8FB$f8nv{4L74vNkHRG9O-Lu?FaF zv$j!pv~Dr4aISqs7G?`Ss@tPB?cuo=v#@`tlC1KQgTc=}g~QWQyHK_(ee|}ulEWQ; zrEp4jK73MlvH$#4B6kLZzp|mH-P?KK&A?Ju4`hAD_dAghsL2AieAU{xYVrN@+e7}6 z_1TU`l*nKEuQl=lTjzwY#UGYwH!Kx>MSJf610Xp70}f@n|3;05hwwLwxBR>{n^>u& zYQE{Fn4sN+zr3YTm zHXcidFdDeyufPq5YbGo-DU2mX*Q1#;7-nqNjL8$MRbuRgO=k6>vWAvCZP84$hvalS7;<(wq)U4qb)}cQ~vh(8$)IxPf4X~l$r^eCwkhv87U#$D3K$7 zsobsDWt9A-`quyClkQ{h8cmc5k4h&IUC2t*kpy!AE_EhlD4s%7*ak`$ReC6}$Y}^) zxdGMr9NAm;XAg`D)u(I$gNSHjtEr43I~rY0E!K(SqLm?+gbsz7I-oUK8VH^umUb=~ z>{a)AMx55A^fY2v8aA?v&jpUmp!qrcrN>Ida*!SVs!zeFc;&Xx95T;U%*(l9u{OhB z_0|PZ$lN~xEej%k*_D0O#KA8!Qd#$}r4DaUw0`TlPce<3M_p|50iT26JNb&4=ECI; z)fbknxn15dE{3_3SmV75b?ZX6TPlXxj4Sld-{yvLN862!@GaA(A<$e;+EQ_{e}DVMN5|iR$-8zuz4zS@$k_4eN5@~^`IEI*Patl=;0DY) z7&xf}EI{r3}qDtos%w%~Ts0MhY@(5n|-c!|*FSHJMr{wC)@G!R$Ll-8bKU zC!wg~`0Yc7-+kx6!9#}*h~+o;zqKD7Ll>k7;N82nJ@)YZci&D3){?n+fJa`c4Z{#< zs``NnKUH?|S93-gpqp8wJ;U5bZdMtaZ6|4?NYlxQ%ez;XM;n_HD;~@yY74OeU`Hlj zLp!G_BBcl8w&?Gg?&~2sV%e2~xwfxO>u@#C3NR{w+k1`HZQfNmk+y#pyD_D0ow@d2 z8bj5>YoETDoeR9ZnR?r8QLnutdZJ!v%iw%18JrGm=$2numG`yqD=WJVY5Nd+MW+oz zuPz@?+DXRY%$S1%gC0F@&)-VCVRMgPO*)Vlfb+X6`pRBPIelY(?(EOU-aGNma}RE1 z_`$8Wln{+En6ZgMS0_FFn^>u!(xHoDpdMJ=bLocGylZ}6Xe*21Zy&!cv`cv3@#EWW zrt1+-<<0<|p^&!3;!M}0UN~0uKf>7D6tHzjhuyjhWMpd=HeP0V#V?$3zfg)=v;HLDcgg&9(LOd_D%2`lr;Bm@fV}<7$h(Q zt|)-%@}K~=1`pY+u{D1ce1%)p6v8co0WwxlBV+go=;%vKMcTZyRXb8O${grhdANNd0S$%ZOz@9w>|W;I}Rs>KFMNc}s|MT#Z!n7vedl#A!#3 z4sC zTCr&EtjQWwbr1~4EHQT6l~bn8nnw?x^*7z|@RNJrI0S&toJ9fu;@7|V)vtc}voAiS zSMV=>SNQ$U|NP^xzWn&~dxsCc`_7^FKlINlgKV@*g4h?QU*B$ zAGu^0tTSPIUexwDGe}w^h_ftE!J@(+ecWm9bX8D3ylhX(I{O`~QI1b>x;G*K@4ZQ4n0Q-RECy`%9 znyTI{!DCOt>R9)kUaE-8(Z3Cq(EuOLsXlWz_HM~h-39l~i zPrL1UD|-96q({F9Jv%-we0Fq)A}e z3w4|JRsAOD>TSHghYmBw*uet_4j+I2y#p^id=uHUw%&4UMIsxGT>4gV8k*Lme6<~U zLs-CCLDG^mr8X`4-c5S+dx(g>t7m-{!3>Yx?Zd{}v~LE#OezaUvS3vJ*7YTPD;!!U zu>Rn4dmw3qHW5~+tOXhcthJdUeDe~oF!R1s{Z{nVvKEAe2re76oqH9)fVM?qDTp;V z&z{4wIdklE6bffa@pp7Aw1xpyy=--Cl|j|q`4FvCdd>Zgzv(YT%rm3nX?o_+^A|hL zgEsPIi{~?p>I8zX=tx8GRS&%pQ$79$zjhjG`nU2{0pD2rsO(6CjO*Az!wa)i`Khmc z;(5SZO)n?4PXZ*p(ZdRF6||JF;j|iIOCRAWWXoxv;)ltpR8FE~vIZh(r#&?;X_a0|SdX;gV*6~26baO|GK zm;aUwADqvS#TuY>0mDAc=NKwb@96d+-jZCmcJ27O`Nn;+2C~KDT;6Vy9l~FC=v^i^ z7umV+nl!ip-r!cT=hmP1o$p`xqhWNPC3o%emGGBmX5HG=%NJffeFDQlaqlzc6{Z+0 zF|%d#y3M!Wzx~=K$78pfI&JEd$#|NH^&$c*5zi%n`AOLbqFHLw zlqaab%q_IRM?3{0*wzmw2d&cB4~AYg79aKEm9anHeZT6LlpExm+)h-84E*|c;p~UF+socmT5Tl(E<2* zdLZq7`bqjAJ$U!6n;D954r#-N^H@0$Ar9I|)6%D{_O{;s2Re-=s)80+%J~&pn8vSI z)%ffSf4Nt=Yk_ZWX6_^txA9X_&iNGi7AnR?8mP&rvevpLKxrJ#yn8sqq$98IdZid! zi`=eTRkO9$jXP=E+c69K>+6%<-7On9)xPJHa{=20UloKi9o(S2!1)M{*ZWfE;PU_Z z4d07>{C1Q+ihIW)j|%FSJ{4wtX7uR_eKz%)_$BlBeK>z<^6`tKdwKEK1|Qyz;%`s* zcE;zjJnQzLCCHDBALGG;^7r80M{i!Q{_Xf{S6lzy;*jb-C0vCw} z{=WPrr~>Q0$wQ#4|MeCWj^jWO$8gCTYlL(sf6M+X6tY|6uZ^xySR4n&ej`dwJ&ppj zxp_B-kiUV2wuEv+3a(zSn4Y6*ZFG2Nd@0nrGIP1MuJyvyHry2UAJb%()lwcj=IzkW%)aH?0Cj#oNjKng-fp8bn{&gJ-K)P zp;I57`TWaY{u=!L_P4+N{U84{fZzZ8&p-YCH^2P(FMmb(&2N75%P&4Y`s%K`Hm{sN z{i-V`j3<%XL_I4rao8{_Ap<`;=5Um5YmTOe5MnwbKqir#`SGqF1RV=n~PTs5O4u(&oI2c?gP zzk_cDNf{TuIdQ(BxdT-w2n$1+yoyZUIW0!kkvt^tyOnO%6=7;=8`hh_X`jFx!cu3F z7iTHo>IvYYYgwGX@r}Q+46wHkV7?HW4)8Ze&KI#E(YqS|lbHeO`{%nG$4(5LK_uk8 z!ui|B?+vQoI~jH1k;fU)5_=2gXI;OP2w>@p2Uz@;_8sJJ#4tZd+I$hf^7s8iFF$@O z=_eU}AskeSs(%}R3%?zJ*@7}?e(q4*I2>hL{H>U)7@Y_C+u^rhT|^%c-sy!z0G1Bl zt~3Fhm+Q+1EO&AErZ8)%HyMec?9NfU2+9(|*JO@miN0Ev6juza0P`3C2_SbS==gw( zzsTVE^XCP}k-_rUf)9B1> zZJ$a!?P?!+0VkLdXQ(sJGN-59EeufqzJsO4&pE#Px;H&)|Ll;iEl>q0$|z(##Ec> zitd;t7~-tq+S=`^TCNIj+BtkuObPl1;vP`kQq!YwFD=52 zRryb^Be!;aG_Tcrs`#iX?z8-*d>cdBcP{u5y>}*KTqb|A@)w)Yy4B0+1YG=e)D04@ zOfbxZ!8Pa3#S6UU)_Wd%>g9KjfAH~Vs9OR2`#=8sx%~alKmGByEdRqFfB(DR{^HBC zr`~z~kz3a!rN!i}ZpFc2uTm0#k;f9SO zLSVFM((Im`VT%2A(hX$nRWs);Tf1?~EkC{s=dUTRwh?@_9r`lV!c*j&+|4*NWFjK) z%Gj6v`;{AT7U&*1eB_t_=09%_9#jo0hmj(#Jn*hcm_8wI6Msbj*1qQdMF8*G@x&wd z|AcWEFhG-p5(hB9IjIN`2dTE&Uy?+Q1#Za<+K^|06+YO+?U7Fuibx{EfJY<2ky zsC#Eyx$(CjizP6`T+y(jn+mh$+cdOlNDWkLf%=#dk(?zxb{4yPZ(SKe^O6m_Ppmin z&*D9ATsrvDU*G10sTSyODtI&DHT3QA_goaay`}%X^2x0w(FCj)LjjxDubH^@*DU^P zi)=(O;;-u0(B~^0d71&RJN0`ThkB*(}5XZUT#;ts;y`n*OY4~SzsAt{3g4AA|~N2+JlvR>r@{-S`< zzdif2@^?$&m>0al;1^>v)-(G6lh^9nHM+Ab@Ynd~PVK6Ju{KkphHED8nAE^Wi;ciq z8ad3=L>%$?Dtjq17%(OZTI+K&LL+_|e{kl^X%olA`)j2Fej}v{y;jDtPUb}&WqN@E z+$AZvF~eW-iO!@a@!a`*@&Z}`s$UY_&zoJNt!RDj9$_imd!Bis6;)0Drp`i7hQEPt z9Khjk=NzRn@Uf<*_Q}UURyHpyi5N$7dem{40CS>&ZUV=gC@WJ@LL;g}L!Z%hMRqHU zKr@v_=2%2Ha(Vz6dZpjj#(}K^_*?E@0Zj5{4rs?C>nBbS66L%&K-EMn$_22wVV7Pm z93falKNI#q+EiaujK@%m;?iJdGnbsxdSCm9rY4 zm00=aqS$s53fC$hD&)?3E8(<@v(lZkK2t(pUp+dLur~zutU3MMDa_BrgN+z+QEn-> zG7`9@=ZLuF`uV*rZH^Zgd7XO$4l?T&)%1y6&V5aVojSWe$4w5BIm~yy`-6*zT|Qy* zY)s2UU#;7)egk8ftX;Wi)>W5le~$izzl@PQZ3d%jqJWpJT!YHI@9{nR-Z@S(=r4c$ zyWjr$cYpZ(AJg?H@mCdu_3!`wZ@>HP?|=W>UwnGz{R1!WxO2<3OW^O+sndk72BUfN zuAV&;{*D_>>K2-+T2gG%T|(xW;;#a@N;OPzL{n&|@qigx!HwbO*hy;C6_aN!Shn{1 zt&IFe@*%Qr7=5*U$96M5KmGKcJ-UCNdl7b$X2b3tZ_%shU2uE!*zpr5j`Mfo#Cyk& z!dtMb{SO!)6vbEsp)vTieteVk2^D|!{PWKe0sSONIPSai)-8+#JZH)TdTd>AzBwq3 zz)Bgc%jK^C?(8=H0DN=~ZnzC(i+4C}DsE;6V64!6){B&miA`gQ z->&r0Co(Mo7n7RrQMF^OJGe=I$F_zoT~!D0IN2~W=fb}24=U?09;?sI9Jf2W#@{kK zH}p0PH~#i`T>KTZqNdrs6l%^c0gTrzoKybNE&xR>ILVM79&4Xxo_$J; zUa2Jr4r=E|J*Q=`Ui8NK-ih)gnz&0jDSwr#4Guv3K{;ayzxuQBH=4YHQv!I@X(fObae7}hyXSstlBY`YHU8Q`1|eid|)ooW&Yhn zUXw2={KYVk-dL=Fj@%L$3JpC7Xl+Er_sbXMHgem?hQ_XN4}Rid7pk>Y!B0!n6^$>f}tl zGRzqITr0B`R(K5&xeZqIUQA!S>E~g89zN#EsdGruyn3zTcf+Pl>({PYJo~D#!??vi zq?0bzlj84me&ciJEn2eDM9a6_`}pn`--N(l{_;1!{T=4#bL`I|_`m-2$3Oi3*FQgd z^61+y?Yj4dwaXXs`vu|*MW_LZY&Hw7o)!K&3Wl650%KCa%gYao!h8yr9KsmJjmL70 zfWB&i30@s;I>@&FFZnkXtyoL?jXUnV7aL%@9;tq@Jv-zA*1+eUdr>7qhhNekyiH8i z0SwDW#P7*d@1Hz*^3+Kfd<-BTJ8~HE9#Ib;J^aoAmkS9VQt6BESO!n<{E{fqh z%jpr-I9wF&1K88!NK83JEzIr3SqtE;*Y>6}Nb^b1@U!$*jre|%>YF%HF z>6zZ;6!;s@FUIHCTn-;Oaq86Z{ZHPx0sC|OzwyChelEIpf>uasDF({7Hc0p6aa_Vd z^*~fr6TvJAhJmdC&~X9t+9jrBv7gWlg5+mI;pkrt(DGIe6L__WEF5-1auF8jbOTNn ztiJq>AeP3#@Bn}1?MjO?y`l#0e85Ow=vM$n0nf(`TvJ{RgJuDNR~7mk@jI)MGspSc z#uLYN80Z##nOY|Yztq{$R#B1gW0<~Q-L<&eh)$WofHd>wnR>eQhQj#kfplbd5ot$M#$m zV|s^#Ms3pcFZHBCKl+#Bd0eXrj#<-I^IK_P3#Rc%GlOEwz`A|>cuddZP`@+|h9@B~ zEd*34UsC*XknR9QUeGI}{OWe!;hUxn05?%hndN+R_VTU742+>Ik`77m_xl%Jf{j5( zBDPFCk5u8X)r<(*k&X7&z1Zp5YJl+dxr^R7IjhgnAzbw>&E_x>6@aJ0Qu|Lt1*Yu1J)*yg)c`*2P0b^z2cSN`ehn)7GZ0Bi0gIF4g-5-b#6oM zhqs^uacd4;_#=i`m`?U9+`re6Gj9FHO&iv&S~6$KxZ%Lf%{XtHffpZ0PE?lyN zP_1uzSCCCL{QVJD3frRMmts~IlSDH%)ulwsGXj_cfK8h*WBT-IS4|jC z+%$%0Ql(uwl<^ZM&04VR+UrO^c_#xOJ@n|Kj}iI|e;IHA_@aKFLy>3>+(%ug>-Qiz zc8>tqW2oN~r#?6ZfKM`a{P?k>$JN39hs1{tB9SQon1JXvO;EYdj0!J4_v~|f7(f^U z^u6Z5S~_?7#4(p$dJ&z-{`nt!`2G7X8D%1%0i`X_YCG0#&hNWJsW5E>=EVk6UfLa& z)E$W1ZDgYc;pPTbbT{Vw9gbiNl!9;K&A+_ioofoA;Vqjs0JAU*EoydC*lfTi?X_O|2W#h)lM873{4Ml0{uYG$Z`h2&ZYgy<&%N3nJ^0qu=pnRb z&Ru)%%D=SEON;e60)p795#+3y%#dN2jn+8o7Fl0({o3!BK^N@!+icHCJPCe_z*?TQ zH7DAt@z?PdC>8pw*Tdi2vG-1$I=27GyXaGVvuGv!$zliJ=wMZEl?GonD)I`>4$Bpj zbuNA@9$Nk;-PJ(?|3rZ2Y3<57r5ElH^0~{0d0%Ne|gI$W`onLQQTA|RhQUK(5 ztz%RSnoyBQ;9o88LR!bcU~|3&nNoH-cXb(AO@TPXILePaIu{n>3F2D;k7z zVCP%{5^#r*s$;{A_6C0Cz{yWOBh>1*e>j)F|Mefg{l!l|e(%_U{V#5R;Ky6mtynyN z?(8^K<}LI$&7i?cu;^fbX0WgXKnq_lD`ERS5SW7`u%lq{LpBVIAna*ah2}62$*k#9 zCNavG!<_IVqO-vCxl2~A+ky%RLQc|`m3Hlt7z`MhTjRU(Oa!(UQin&}T)pEcdF z6YszO-h1z#JY{k2{Sz)Zar{^c)@b2-(8}?EJ&=f-e&wZ?UM2vG(F+N|+O_S``+j^Q zJ&@+joIHNiupbfh2R5}p2Z_B@l&QT{wLV_nTMIWiPhLTnX~$m|c!PNHPO_2v_-m+J z*`6$pR?logt~&-d#srHY@3&-dN{1|P*7xSisSx{X;1V&N{0ToLib$k z{&(-Ze{ufSkiWt2bUF=SeZH>s`=!_;4b(oGFatX88>L% zselvhr`_eq(f3Y&{K0`|?`!-`AD|+z5;#TN3g7O1xGZ}qL36EUt01*46ukO(nfB6e zl>EgW-TExCwwQhUZG~Sf%_iSS4S){3z{OuU-11;G;x@Z; z1FtX5C0q)4F(pQ5tkBdKNyJh7mBn*mV{teH#`;W|Y2V-2c&R$nM+VNO0#0?#q`2$5 zLHZ7jAe6riN=*T)6)@BRU@EJH^Xb~;Lmp|^(@Mc^5g01LUu~%-cf45sa=?T?kEM*k z2%U68LL^0Kl5#T-|aQ0UwEYp6GY-j{H(In6Rv zGN&E0t`YTB^>;$A%HQ%nd$ILBj{?7O(kDXQTauiej+|8CR%Lu{!OoqL`hv1Qb9rqf zG(n5TZ8nW|zrm~=&K(bsO{dkQGT?>3dV<5>OE{Tf#LlXJsg?PQPax-B6|U1#Kh(UU z(_&3tM0JMuJ?dsp_NdC5JCQBjgkhbXN?;}|KkxhtFEMs$ZrPvl{_;d!zhTYF#W;Y6 zdUG*A8xS}#-QkS?ClmQH0|Hm9TC?%S+wR}-+^Yvpeth<)KmXP5|6|Yv{HNdl?Cj~| z@4WKDQ;*(t6M$MYZw^K6Yd`}H%H`KATf)NWlNl`gGC~!(haG|Qn*+ZBm>-|XRp9Tq ziF87qyKv#c#Y>kg0_M{l3Hyo(6R(_b73nh6avcU)zU@-i!U2q2=g; zwEZyxu&%cU@TBphhh2ODqW}lMT7?O^YI;<2bnMSu`1%>AeN_#tZhQDk6;FZFK8SfB zy>OMJfOeXd7$)=6_kbC2e8EaF4%!9}YHf zZk|!IIrnD1mayIZ`P!9(3%m9c!B;=Xm`4*b;xG73*2xU``{?7UUm~x%AqVyRmhTt! z8vw@xY|a31D@mn8ExU+jEP5MrGn{ynvQE&1v^fQ=F&Sdb#n};O8P6MqTSc*me$oWpK|U z?2J}fBw~g#tqP;GZynRBgg^OfvWys+tEG{+=W)tkTLxH#gI{~#mW$dmN@e7z@t$n{ z162zVV%116Tt}6TSl518;md7&iWsRmS+Cl8=Y5Z0tu%HZ8jMkNn)|J96$TV|-aN9O*piT^PQ^N3U3VOp} z`FrWeag%1uBZ~9db?Y})Vw>wXtX)2jae%SSJ3hu`bVr{samsW&B6IP$5GuWF`Eni- z2)yCOJ09He{A=$VdH=&tKKsQV{4Ld)X4zey{&aMx zTaMX@VNV$Af#F0Zjvv$GFXETGXp1jh&aoo#94& zqmP(;_yOhA`=?GLe@|eA<_{C}VP(mYBL~qZ`heef{T1;0^4`5KKL5-!&+OUr^v)+9 zyz`dLYYo5}KiU+O-?b^LkPQwK2TkQ&^*3PkHdxfMxP6$jUBt$e;xFFZfAA;I58vmJ zyXvi~pF{X7!r3YNWfP9tj!>~!JtK6fO}QBcOSgXM+_W812O(O^+Eg@$yx&5oc3X>7 z=Kw6Y@f^L)j17L z2Wk30n2+_DI*7iEj9==2mkE7dsrC70({A*Q&o$&i=l3n{^0Q0a0rqDHJ{sh&7;YZm z#9k#R@aQ4($L)FS&O~+@0+sM%A=vEDIAq~+i0kT(zI|of5Zt`OJp`8w?kJpKtct*j z^Ov2vRcv@0hcEO?Tub0v`29-&ZsQPQZ0^Zl(JPb716%;c?Mn%Dfo34=EVX{HKY$X!O%&*F=tM?Gfp6d6C$qgTSiRlWUF3F$=;|(sD-?=o}qfN z;QKZ4qR1rBbA0sy#$p$ly>QV2%+KI`)KD@;NRrgj5;O=6kHRE0Au!Q&EPpfh(dEV8 z%g0#cuLkIfZer((z_KRDBk!|b*5{CND0aYv6f;GiRNz(V;Amkj&#j<2?fzTgKV2PB zddu1*{3RDgCG?2-*>;A`Un8$Z1;0cv^NErTR~i9S+T>FIeA}^OQtAae`}YWJ7MU>9 zb5lQc%>?78Z2Q3m=ADlM&IYPxM{JP4L=TM^G1LPkDB2E4R?Q$d z7Dp%6xZWRSD=y$b*Y{pq>t|Q+TD7vvUFjY{Zp|>wq5)K+fN2j69XW3D^!ZCyh~LdO z@OabBVAFN0mt8&S@?o@QY#lHJ1Nky=z0QKam}8a_H?ev(&KsD$@y6TleeB6+_rCV_ zq4z%i;@5vF0{{DOzx?>bJ1;-I?ZG>5+Ia0X*q-Oi!uLCuK{OXH<*8e>ivIX3uUWnr z{!Y3g`WNbY2l3RG|97Y@v0+0DjNsw8Y}8n?WX|S1SFhnjH>|yO)yidMlR}W|k!I*~ z$6mPq;Ya9v^tibQ;OEi5c0uABngV)}0a%wM1!ZhW3e%2;z!xQ4+ScE4 z?oXcFG^@Ogc|Jt&KQ<$DX2W3H#ojr72mIw`dI*ohZmoUW_{$OcfnTAI>}vq-K{&+g zcqOw^kfuVjBy;h$;nqzX;%dum(`MbJB(Mv7XH}n({focf((2sM%Ur{3 zCw;pmJ^C^OhkNv`RzaO&_bFdTV6VsjfV{Pf=I0u7Fyl=ddxgzt#kE+U!EbNO1wyav zC?-$Km)@Ng{EQUSXtF3beCj!gRzk^3koHY5>&DUMKCj4#qwfhg2U;{dqHUa4vEZD1;b;co)9q%sTDz6Dz2ugu4B&)v=XT-3QmJ(H^(UzJ%L05%esH^%D!zF+r@C4#bro{_v zuqaiS-evh~FWUleZ(3+7`?FdumQ;iTN7Md1mJ;)`qA&UG0Wim)7D&L9jchA{de~X` zJ(5aM4^sJwLmCOBD6)@;3>LYC-OTg=i~t5Ak!}Tps%+Y!J^Hupi>t`ApYzC(qkG2Z zuy?qgUp|bhSG44;*egCTs-DJQzp^420F&9dBx|d!nX|MkknIBXX+4UM@KCg zZZn5Q&gF!nU5cYojMj}wBo}rIIx=$&f1srqk8q^_g<+=6sPGq~^bq$XZ558(h*@tl zfJWoe0^(I9>;3QZH*97}yufN>%Hm8;C{VZc(n$WsHuljrOV%r zx`t`7hqZMle>?qLo7CQ{CI8isQ3Nl|TS7~oWIH#+&b4LJhP5jfOuJ&#rJNo=B7Q;@ zk}z`)uv>)JYsE^^*_gYPsOb$`Zu!YQq#f9~=j8(*|MK6Bz51^|{_LY8uRq7INVnd& ze&sTMyL0A%Upmw+VU*!jghOJRTC*Cb@EitP8bealAv_K=M|I&7f{xjR&rL`>4Wwb% zpNUGGI1T=;W{}m*TW;LEiEdJ>Avk3P&ggaE_vYJwayRn#F@`sOKiYa%J2%`8{ZjDWQAQ>lHG!Np&J z*>IZXmG{V->EjpC%k%HLZHLuO2Or6%1!%Cj%s3nON zi=k>b7+%(-p|=*hMYb-yxv)XmvINO!1{cHzq)&I{ywpz zQckvX8gN z25p`oJ0kgMa~S#;{fqs%zVkbssgOH z13H5~sMp1>NiDGb4I3tUQx$r~5t?XBwLA7`Nt{VI^o^J;!_O}j7*l+I}D%d5k*!x#Bt0sJPlPAP^aD9=S0{0^0 zdC1Yg@VvrQC7j$_LrlM6RQTx2@}cD8#Ng}>g!_U3?a{eixPOhb^1Et(E~Mt-vgqQA z9cKx%aXJ#If4kzxM+mbZ65N}w{AHnbZU-lH>uMzpp^XE^u|6BpuC{LtjN-2hZl&s8 zFQ->n+FEkUn6xXMWsyq7-*DH3MQ~=?9mx#sk&A}VcXrl%;yBlB*t8`NH;>r$>#top zXY!a~h*7?#A$;`x!39iAJ_h8aAdj*d{#_%2-SdVUZo2(}J@20W`5)o$pML+-_g>rm z_`N^A<@&WNmn=xGIBd`0ck!|?n+CCuBz9?r>!b%TE)hHk{Jeaj1vX>|(s!u02Qo9^ zp}_t;ZPt9o_`QDX%{LjBx#jxJ8`m?$_qw&$t>3hnaoTRX((V$?yp{%+g8edkX3 zyF2{d`%?HzJ;*>u@YkyD=n2BEioa*io;d@ADIa|ZfKO?RKKcIp?_+`{7{+**!^B{b zEQ{389D@|lloy{P2jx>co_O%C+iqCDiVjEV(=PVmqDB$o-NOTT;Q7}-HLX^9CTn)XXSG?t53>D^Z?xO3S3hL=-c-JcPn`vBybLw z({=7#0bJA#fMqc=y(P|cZ)@S#O=&%0d7@gh`96x+=hpRT)3D1Rby`HUfVF^ru$L+ zztq)%FBAD|9o^(%;;)owNlGDp6Mr?P3bcd3NNxK7D+p_Up6Cvj;y2x7%_+r+4YMHW z(In~ML;a{8lt9L+hQAHPHaVz$((Sftiqc_KyXd5%`>(k$(2g8iWjb6{j;)f&Uvw7DB?RyV2y@kF)OQRQww5$Ca~$l?+`}-|Ba2^qcbVprmV&{| z-sA9<`|ZI@PMM=*aV>Ir+6SzY#2kpj48N3vSLdTa{&GjPK$kheirVVhI=d?10GNuq z>R+qnM&xX%?CmZ-yA{OS?zN|Ne!7DVCH>^gc}XL{GX#NYXJdh0yJF!CazKZ_+^VD` zw=sA%5M8pACnQbS73HSEA50X*>Mi%}dF%9-fB26-{l{<49(v)4yKdRKY0Wi@=aHgy zmd@XpuEFmrdm|X7v1ZlsMFcfW95;F-hGt43m{(gRaF?G&Jt+l zHAq2;nZ+L(Hz1A2h~U5fJEd?Wuq~zhq;nqw;NHV$V^f6k-%{_?zzy1Yrp}qv&Cdb5 zon?Ltg$`OmyFm1t-+-VUv9S0W>I75^gW1g4ycc6`+lV{((xHTKZ!ZuF4F4~JuvjjTi@$u4K7Z>(>wrw#8E{(pP$pq&z3JmM z?{ksjmJY$pvIZ)5{ex>u z$ZNs(i}ktqYkwr6Y(Yfpa|XXH1gq)qDBvKt7x)|kw@Cqby=`k6*x~OvUf}dWA~{ws z9hMq6Cg`xY$KyW(a7@rG21^3NT#K_;w=#Ri)T^!-W1XG=p7cynGo}8u+O^uYai2OR z-d-%uJ*RKfZx9TQqk*9l(MhO|X+*xvp%RfjTzT3FAEgK;T8~3V#`7vGh2p!suke!8lqv`jEPr^GVI)83~Zqych(rw(K8r zE@=@|5Vpo=I|>zlbEbL%)SlQ3G^;b-ylow<&!aD+r;$d25kpG=6C^E-&4{H+{XtqW zk-Bw9H7!eat?$~<(Z8lbAr)w%&g*8&*mL;nXXjwG98t{z`v?nTj1=V3?)v_E2l<}R zGC^44H-ECX{S{=rDEv|M{k9v|Q@~B?x>G@z%O}8taF*p5nb;n=bfoDgm#ozPy9osh zezkQmsvaI-vUzGn;rGZ0RW=689YTk=G-6k*TyA^>9rA$eoCPbl-2L?1r+@v2KmOqt zAHVbT{Wot~f9Z}FVFvK9?E{t(>&)q+$ zo@cyXtj`FOefx=hVSvHt-(!SYefW|1{rJr1pPe~-_LEOO`S_zKV6c4p{o}_^yniBL zSmelx4I26T7DFJRfA{TsNeTSIbGvsu_TXK&ZnYG6g!|`zZzkIUU;d}~+CjKXQ*P8s+ry(-e7Z8NeXIXdW6R(EZ7}z(0no+c z+5}|iS|pT)H5V-Q0heu@NK-i%khV#2Eh}8oTkCd|{#Jo-x4u@klWHGVXboaTuCz^o zz60-E)RVr|ps4f9XVnMxKi7}%6Sz;`z6u^#_Vu&aFwno4pOwGEMvk2@3HiHt`Ra9a zJ-Us2Yt{288J`*7qZ)aDw)C#9UJcB~Sy}Mx}9bX)0t9zA-fyHzR-5y|;F}jW8C!nyVGG!dkm?%3b0$!I#`})Q>=n8?Bzg2wNA+lx78go-pP`;GFx6q3->zb9T z%@W%LN721nqp5REzr<+4so4V&zU)mfqyY+s-M(gmaa-xMp0)+ z_gb46WmT;0W|9$t#cH!!-y|@V-sCBSzRa9HZ7Rv?jq#v~or=0tO)A!k2NndNpwu6T zK%r4}BBg`hv1nfkFNPX7qh~eMQ&aE+7wfb>6Bk7EmSZ6xfeDHtqKrz>{{fz~q$oXw zCM^qX(R^*s%!*%JmPOTiNJMye_{&%bO2=X0uPHG6!bv}+K)47LC%}MXt~cA z_$7jB{dyd@*DTQiOtW=3zbuNp^=Fo!ocK-f!Eg=G4E8o<*1{F*Hr;ePiT)mb_<{TH zzwchdMyyE~_MCCgA9(1I$DVkc(5r3Rx03{)R7AUX6a0+#mo!8~#q8Tp2cox7zsHUp zIrbj>Jq>+7Im6hApPfB(_S4Tk6~Ibh%4sdob_hOBIbj^u(ZdI*O5bz{!dIezpMUn5 zr*}Mh{~b49zs>|$__2Aa_@Nkt=#P}EogY3h)eMa+6|4TRZ9RE=Qu=oe{>s~Il@}&1 zC@!;KLAUof`B2pX^SBg$JAU(#jV8?_TavcpRrgxtD!tn%))T%cOgSgFUFB42G8=gI z!CC}v)1F`WTm}{f*+xPa#B;1Vc%4qi-;%l|c@@2d-*X^*E`aOIIjwe14f38*mi)H@ z_v^vimd0{n@&X2WG4bTYDFi;(9~vVCx8L3j^MOQYjwq5g}?fW0r#yv z{@$haIl~|YzaFQ!O~)hnn~Wb7dku3%E!uaBvzyB1-0`;n%obS_0t;J98rvOxlY;}` z4&ql=Fx1tg27fym>kYQpKgl5ICD_=Os(@Q2%K0fJfuXResT0ybAUVu@jL`KqvjvHy{<~_@WXhB&;1|GW^abkb(ATFtrO87{Py!g3 z#L64z-5AT*;xCd@A25lZtoNxYtP6ak3y=(ZMC{c?(uGRbA|IRi*}75U8ga}_k9+Zu zUSu~O+y0!CXF>5asrIdf>hLxpZH8RR;rZ%*ZwhS|6eiwQgkb`>3cm_q&JFr<5RcT= zSja)nGr&)(irD!BH;m^$^-~fAA>2+=o0l7G99d3SvowFEU z7H-l5%Z8J1Cjk~MD!C3kxu0N}t2>+{5DOP@em4vy^opJ2tj=B~Za@xpB`@=t#`w&F zxY$Xy<;mqB0+=rnXbM7E5|hu<1kH29 zL$h=#Sv0PmJ!AURsZ*xST(IH6eeZwqt6%^8!#8&RxsW2_+w;Z`F!|uJGs`jjbNlUVMr-UDQP*yLEuf2zi!8dtPOoT zRI_6dJ4-=#(A%aSDa$>qd-{wym+3(GSNS&sq7uRdyWX_m#am~5X>vJl`b%pwr?tLO zRBa+s(D zLk;|CzW4T?dpBPTe;w)mYf4Pe@c_s4tOhQ3uYwr7{`hvKF@>dNPu80o{&oPi-Fg>= z7haS5D*R<9=}T$+?E_e;n<8ebK-}IE@#_j2*Clv^-(oK~#v7aj96@X3FA5iTRE1)> zw6L71>|I3@Uot~r3Qc`UtQWXfI{xCDwf(E}S6gP`cfb@33ZSpLw+UY*7z4TV-i1SY zg56}evQ;eOyNwt4$_W$5d^_>V@e$aS|JfFHE7Yp7K3jPMCT-q`IfIF+<_dmmQV_-k z?3izH0at|_L{cRr^h)t7eMi$Ph(8(%aRWDnqIWLrZTL0zN$uKecgS9qe>(hl_|z2E z3`P*r0mw3xZz+HA{bGDpyT*F0<=G0PtE*r{P{cR2s*)M<*srNdx0T`Pv~wa&2uDdz zA^FR4+_~igj!e~JO$*kvA7g0AkYn? zeFC7z_&bEZc!2TbIw~fXWV5L!FWcS9SnKgUve0H*py9WM}>yoij;I9tgE6Kot#-$8%I!yJO;OC(P|JfleW}M5_=}XsK zfAf#;y#HZithPPz*kg}A{Lq6BKKQ@`{4wJ1qmMf3?~a`r0gl+`-PiV0m~A4FQ5sLm10sOyCo6zU`qq!yJC@?Dv_WJO zio(ynfa=C2mBls%2DegZWxKApAdeRtxO;C^R`49Ldrt?;Ny*f}3cspIu5X6EnK3lW zx2&x9*$P0qoomkFZzN|ZD|XKTaB;X#;5Ju_mB8J{Hlf`iSIX9WklRf<95*~in%5b5 zYJM>e$P8yu8oSP>e_DS2UlqDvx6%N*vOXvEM&$2|IhA;lkbAtp47%{7qx~9Sp9p(m z3>tr1R*i_<7VM1hEpxNfMf0WAoru6ni;hLXtuXqj)AQ|!;WfH{(3(Ab|jOyzh~R))S*0+n~86Tj@ISSB--ErsFM zi+JS}DwIG}t1m_V@`vu%Y8%lVMmV8jnaj^7>y&%xu-05sn-atjJYu*L3%SRW&{DbN?@kG zI#)<`p@+gmo)@kehI=kr$)y1S?2)=J9xWURo3L6hg4aRlT5HFYsSlX%9D)cY>wF^O-+jjE5am&V)^QK&G28{5RF$fuy znvny|;XHT2;>AmsFSlX3n6%`KX2kFRs)-ZEPhN7*uIczf5Kn^u@#Qp=5^ z`D#XPSVpikeUJ40LSQ^Z1YpgZJvDZn@Rw$%td4^cw227pF0w0&mlw~^y_Gr$yM*7!q5YVOg+b3`!8?Jt{=o-L= zw@hMvj?`>=v(YY;3-3BRazkD;C-Z;zcdX#GtiQY{zUxiLWE%n=C#A>VP#50zQQH&1 z=Pb>cb*IT8Jp0DqCVcZb10UQ@g0tW<{9hHpYriqCz0!fuQ7Vg34m&t&ZpK|8=Kc;d zZ#=Q{sS152xp+l9V|=a%tI)P|?O=#=rFmBFrqI7FF!l{RKKA|x?;m*n!5i1C)Fg$# z41n`g3S!|~mf?n2(V9}k?OeT@r(Kel9)8o633{i)5(G{*%JfG{IED0uw_OQ+`84<1 z(kF0V|7w9o@FLVR0D~qp`Kt+9{;pXAe3|5_=Yek$xC?rgx}BvN{t8@a?G6^->k*c} zB+0tQ3dewx;&1%FdVu*OiiCm0i6b(4C&p)ekn%zHQk@i05w)SA%2M$sfAiYepQ(IU zsxIzO4S^{PyHTAzSQ|qz&MFW1)lJGK^6pF#OdHFN6We}svt4zED*yo?a#_nVD2>r6Q=Dzrz(GA zn?|F`-_(d&c%>&E99tw~#*AjjKgj4%Vi>@UTdn77m96ZBb0F+>^0GAuJEEaSaeohE;qc$PUZFOZ4<{|U;qljxfBfku zr`~z`?#(L}U>2G}nK5TB@e+%d5;VOE_b&i80E@?QHK{q~Ouy>N@dPd=7?EFn9tD1& zw)Og=*d!oV&0vh*>u>(ay$^v|qMLW_*uL$FZI5e<#_~+kD~9})zVtn^>(SGu!cWH| z`h=K%h%UT`Fe1~Xi2U|+Gt$|67Us&{&j`W#X>>51kuiIr$*T*2v$bmZXS!<7Y# zVF+J-dG9k%k^Kt!OSY1wabw#6Cuz3rPP% zmBj8UfkWkn<}6@Ybgu`h-w5~J)>jTsKfdf3Asl5W`U+mf-)}-M-ghvpRZRQnJ(s_3 zTeJhR&a@KZf>{_R?z$oh*`h~YX4t4tUq5`{qrSr4K>!bMxpt^i4S?(P`IsELeVp89 zLE*o>{$IhDjpT3P7ydTyFKu@o1oFTvxrWpmc0Mxts>feruk3GR$d$3o2V!|P+1gP$ zkw@f$*D#hwV6U)1{MHfx41Z4^+WW{&Yggi>5pD9f*Y(KR@K-~!bnWrd=qgLWxSIy0 z(XipD(NiG(hOIZ>a@#;6jtbwBzUH|U@3o)m*Cm1<0HejFu*|j3QRwR|E%!)Z*3mPm zIe-&x1$o7Axq(AgG_Bn23Vz$R*`TR-t`@(H>ppqWwnx+IMlxrJvGrd4(- zXCWn)1XJM$8!7cy%*YaaOgh^7K_MtdsBkIkWFA{!JYW&#l$Z`hFFt=P`JUt$FJc z%0K7pG`h9Qq}uh4{>#ZW{^m$#!{9*bR9YswVeziYU(Sc4OWzQi{__l_Glq!Ui_7Qh z@CPI40(5>%<0Be>;UxsM86z&EemRlv+Upo`tlitj4gG)NcFxeiDT|{VHODWgE?@s>yS9y)m%{}udQxo|f8olG88`W`JN zgkq&m<2Bfx*V{bC{w#m5o-u_11r5rl&{{O)uZdvrJIp_tIs{_YG=6)T(&p$)< zjr-|+v|-IPB(gU3yTf_V-b$Q7Vt8+?qLhU>B&PKF%r&auI=an~K z;V+E+%98fB!Pl38;Ags_)0|w8&PU|lFcgqM2cOpb%n$9gbZ|5Fiq1q`IdFi6TXb$s zh$RS(`6ZI$C5gsWy?N`J!$;`=eE8+ZZdtdAI0^XM%+IpV(g2)hvakh|9c#;QEQV`N zA8x=cK(n(W^=`n@<#TSw0YjcKIVXP0UPl@4NWzO>4x1yj6wo<9;kWn;cY|SFz(T$I zgkAua3N`>%3tQl7MnQ_PS=+Ks-ae2uIwOG9zS)qS-5v!jdlA6}V7pw*tE3pf*YFbt z1{|HV&ww$-Dq5d!FN{g@V$j9*+WSq(Abl)Axp?a!3O*(y7FH-7M=VV9FwYTJ@;>2 zy-+SgZOqS$mXLY_{Q5MO{h6on+Ev#u2%&>^jvqHxM+eUbww98>3g7~8erqE}jhi@Q z{)%KK$g@y4vXpMpW_mS%60}OLW}H_ln>r_Y$OIG zRMNaf7Rr}icy{-$C-DB>vYBL^3mM7y%5e;&NK8FHe}2zt2j*_(r|YlZpEe~d_Rh7E z**qvbDLgGa0$P|GXf=QOF0V{t4-Jsrq$>mbt)F26B=ES{?v%s+9AGfp>ke*a=x;$` zP~{7-?I7rzaP1qdt8K?&{jS;0wb{=}fi6&Q`j_LQfGMFK@{>6~Q@eDesM~b}&T+br zE~jssR@gJpO%b}zbZquqT4|?ZQ(&-Ev!JHMU*~gX?feR~UyI*P`3mO&{th2CmeD>; zL%wqDhRs{k`S+2>Y3w~q<_+_!?I*-9!B+B@7^_4!m+%dI!&#s!W(BU%^=+sRL;Q~Q z_sGF~~P+V-c~bp^~w}R1xu;YUwHlE15uq259vk`qw^0 z>^jP$H~3=s6x~|Liofb2S!drM)Gu8<$H7|--scn`+`Pw}Tv?-wz48|f`-Zc}nTjf; z-Ouyh@Jp4Fil+fsZE9%_P_LJv*z7?CVHK2$2xqa@T*8j2MU;q5DWDc|wlJ3CTw;Hy zOChaeG=;xfibXSBgI(HM16~+~Dd-zTL*g=16=5jA9&MKFN@RtDXDIPk=DNa*8$&Xg zGVlhMt^d4#QJXe_dto{zQPY|Li^amTG%%6ShDxUoazip1-@I}8%yGksl(Rub`m4!Pr%pAF z%8cav=m~pZ(4;j9qM9dvr%stVZRWBq_ddDrt%FAn?tk{dn^wc+sZ;bB&&jaC#yYmv z@OA5n&scNq%4_JpbTxwjUzuOq*l}0*6Qha8j|uw%KVN=Xk-yQu)8}1t-R4{FdXO6L z>8DEo?~uQs*D)6`K5LNPv2(|+r=EW5sXb(U2EVOd#4z~QTkkraAOhIfXS@EYe)0Hz zcGei^&j9e}C}9}<#TTES!3=%oV>bH8j990&K%ab%ijzc?WWfT!&p);Ou?O$I?Z)e` zTS+e}bF#Z1R%q>qOYraJob$x z;OqD+U#m#jzwHA!a~+LY5eN?OH;1ZEVJcs{H_rE%>kP$ZZHw%f20=TKLHZ8pU$NVr zT+I}C|N7L6Oktyzd(yVL{3ZH%?!slO)>iH-dmjz(_w@n(R(D=7D{C{12M89s5xx8j zOa6wym}D%~(cEFVj=e?zWAV4sm4RDq(PfP83EO5bhMZDTK<5=As&z3oSqQlhybv?I zG_O`?WLD?)g>tbr0FDB#H5{=%pQ!{6&ij)nU=ADt`>_UKNnqfq23F6CUyi z&d?SZ^VUv{?Y+CK=3QR0Hoo6Qj6}4=An1kofT@PU-`QBu=o;j}3(8B2kx#*B+`Z5@ z;#Kqppjx6WU`)zd%LKpjSBhn!6i(q7?4UZ(Dm+#Qif49f=^AwgmkY7*TMl6Szw&n^ zM@fbYM59yGDk+$uiRd+Z zBq{h}My5I`s@m`e8uUSm0he>JqO#a&mopK+*~OYj>!|&GtVFCqQi*li;k+84DSeEH zeTKi-ne)wJ(ACmRTjCPfth}zV{WKjz{vjhqkENm{|JV0usW2QdBkbt_KA&3a2S2>j zm@4(JJ_L5C8Z5ER&AcBEFNq~DOgjr!r+HBIY!Q=N;nhS#gI}Yp{GLo~aS)Y$>1C4^ zU;mSbAK&rRllm{8c#PVY?a#C0~DmQxqf0hAdvuzz~WUTR`$V-Z;5PDw{2a&cq&6M7-&X|%mEna zNHlHQ40`h7av={TVlgPgs`o6DFMg^k7(IN3e!-ufIrH&Hj?eJHX~LmTos0w~L;kyOGYsJi zdv-oy^5+{iF}5)c5HvhajbZ(#ES(V3HdBA{I8gjyTl(skJ5jgLwX&DB@|XYh7aGgk z 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 z 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�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�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

GyL@zpL*;;a*n#)dB-iCF?rerN^7B)6DsY1 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≥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