diff --git a/CHANGELOG.md b/CHANGELOG.md index ad9f17a42..a1af1e7c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Change Log All notable changes to this project will be documented in this file. +## [2.11.3] = 2021-08-04 +- Bugfixes related to NWB creation for BehaviorSessions ## [2.11.2] = 2021-05-21 - Fixed mkdir error for non-existing ecephys upload directory diff --git a/allensdk/__init__.py b/allensdk/__init__.py index 78e839e3f..2366dc9a9 100644 --- a/allensdk/__init__.py +++ b/allensdk/__init__.py @@ -35,7 +35,7 @@ # import logging -__version__ = '2.11.2' +__version__ = '2.11.3' try: diff --git a/allensdk/brain_observatory/behavior/metadata/behavior_metadata.py b/allensdk/brain_observatory/behavior/metadata/behavior_metadata.py index a057e01db..493bbfda9 100644 --- a/allensdk/brain_observatory/behavior/metadata/behavior_metadata.py +++ b/allensdk/brain_observatory/behavior/metadata/behavior_metadata.py @@ -238,12 +238,6 @@ def reporter_line(self) -> Optional[str]: reporter_line = self._extractor.get_reporter_line() return self.parse_reporter_line(reporter_line=reporter_line, warn=True) - @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) - @property def cre_line(self) -> Optional[str]: """Parses cre_line from full_genotype""" diff --git a/allensdk/brain_observatory/behavior/metadata/behavior_ophys_metadata.py b/allensdk/brain_observatory/behavior/metadata/behavior_ophys_metadata.py index b2c597cad..537e6b34c 100644 --- a/allensdk/brain_observatory/behavior/metadata/behavior_ophys_metadata.py +++ b/allensdk/brain_observatory/behavior/metadata/behavior_ophys_metadata.py @@ -25,6 +25,12 @@ def __init__(self, extractor: BehaviorOphysDataExtractorBase, # since it's only exposed internally self._exclude_from_equals = {'project_code'} + @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) + @property def emission_lambda(self) -> float: return 520.0 diff --git a/allensdk/brain_observatory/behavior/session_apis/abcs/data_extractor_base/behavior_data_extractor_base.py b/allensdk/brain_observatory/behavior/session_apis/abcs/data_extractor_base/behavior_data_extractor_base.py index b74a7816f..6ca354a75 100644 --- a/allensdk/brain_observatory/behavior/session_apis/abcs/data_extractor_base/behavior_data_extractor_base.py +++ b/allensdk/brain_observatory/behavior/session_apis/abcs/data_extractor_base/behavior_data_extractor_base.py @@ -1,7 +1,10 @@ import abc +import pandas as pd from datetime import datetime from typing import List +from allensdk.api.warehouse_cache.cache import memoize + class BehaviorDataExtractorBase(abc.ABC): """Abstract base class implementing required methods for extracting @@ -34,11 +37,25 @@ def get_age(self) -> str: """Get the age code of the subject (ie P123)""" raise NotImplementedError() - @abc.abstractmethod + @memoize def get_stimulus_name(self) -> str: - """Get the name of the stimulus presented for a behavior or - behavior + ophys experiment""" - raise NotImplementedError() + """Get the stimulus set used from the behavior session pkl file + :rtype: str + """ + behavior_stimulus_path = self.get_behavior_stimulus_file() + pkl = pd.read_pickle(behavior_stimulus_path) + + try: + stimulus_name = pkl["items"]["behavior"]["cl_params"]["stage"] + except KeyError: + raise RuntimeError( + f"Could not obtain stimulus_name/stage information from " + f"the *.pkl file ({behavior_stimulus_path}) " + 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 stimulus_name @abc.abstractmethod def get_reporter_line(self) -> List[str]: diff --git a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_json_api.py b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_json_api.py index b0ef19b62..3540675ce 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_json_api.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_json_api.py @@ -51,10 +51,6 @@ def get_age(self) -> str: """Get the age code of the subject (ie P123)""" return self.data['age'] - def get_stimulus_name(self) -> str: - """Get the name of the stimulus presented for the experiment""" - return self.data['stimulus_name'] - def get_reporter_line(self) -> str: """Get the (gene) reporter line for the subject associated with an experiment""" diff --git a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_lims_api.py b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_lims_api.py index 80062557d..0adcd8416 100644 --- a/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_lims_api.py +++ b/allensdk/brain_observatory/behavior/session_apis/data_io/behavior_lims_api.py @@ -4,8 +4,6 @@ from typing import Dict, List, Optional, Union import pytz -import pandas as pd - from allensdk.api.warehouse_cache.cache import memoize from allensdk.brain_observatory.behavior.session_apis.abcs.\ data_extractor_base.behavior_data_extractor_base import \ @@ -254,26 +252,6 @@ def get_equipment_name(self) -> str: """ return self.lims_db.fetchone(query, strict=True) - @memoize - def get_stimulus_name(self) -> str: - """Get the stimulus set used from the behavior session pkl file - :rtype: str - """ - behavior_stimulus_path = self.get_behavior_stimulus_file() - pkl = pd.read_pickle(behavior_stimulus_path) - - try: - stimulus_name = pkl["items"]["behavior"]["cl_params"]["stage"] - except KeyError: - raise RuntimeError( - f"Could not obtain stimulus_name/stage information from " - f"the *.pkl file ({behavior_stimulus_path}) " - 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 stimulus_name - @memoize def get_reporter_line(self) -> List[str]: """Returns the genotype name(s) of the reporter line(s). diff --git a/allensdk/brain_observatory/session_api_utils.py b/allensdk/brain_observatory/session_api_utils.py index 45dbff91d..5e1689421 100644 --- a/allensdk/brain_observatory/session_api_utils.py +++ b/allensdk/brain_observatory/session_api_utils.py @@ -17,6 +17,7 @@ from allensdk.core.lazy_property import LazyProperty logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) def is_equal(a: Any, b: Any) -> bool: diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py b/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py index 59c5b841e..0537295d2 100644 --- a/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py +++ b/allensdk/test/brain_observatory/behavior/test_behavior_metadata.py @@ -246,7 +246,7 @@ def test_get_task_parameters_task_id_exception(): } with pytest.raises(RuntimeError) as error: - _ = get_task_parameters(input_data) + get_task_parameters(input_data) assert "does not know how to parse 'task_id'" in error.value.args[0] @@ -285,7 +285,7 @@ def test_get_task_parameters_flash_duration_exception(): } with pytest.raises(RuntimeError) as error: - _ = get_task_parameters(input_data) + get_task_parameters(input_data) shld_be = "'images' and/or 'grating' not a valid key" assert shld_be in error.value.args[0] @@ -585,57 +585,3 @@ def dummy_init(self, extractor, behavior_stimulus_file): obt_date = metadata.date_of_acquisition assert obt_date == extractor_expt_date - - -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' - - -@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 - assert indicator is expected - assert str(record[0].message) == warning_msg diff --git a/allensdk/test/brain_observatory/behavior/test_behavior_ophys_metadata.py b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_metadata.py new file mode 100644 index 000000000..1e8c8bf5d --- /dev/null +++ b/allensdk/test/brain_observatory/behavior/test_behavior_ophys_metadata.py @@ -0,0 +1,58 @@ +import pytest + +from allensdk.brain_observatory.behavior.metadata.behavior_ophys_metadata \ + import BehaviorOphysMetadata + + +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(BehaviorOphysMetadata, + '__init__', + dummy_init) + + metadata = BehaviorOphysMetadata() + + assert metadata.indicator == 'GCaMP6f' + + +@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(BehaviorOphysMetadata, + '__init__', + dummy_init) + + metadata = BehaviorOphysMetadata() + + with pytest.warns(UserWarning) as record: + indicator = metadata.indicator + assert indicator is expected + assert str(record[0].message) == warning_msg diff --git a/doc_template/index.rst b/doc_template/index.rst index 1eda7a7de..b56c09f54 100644 --- a/doc_template/index.rst +++ b/doc_template/index.rst @@ -119,6 +119,11 @@ The Allen SDK provides Python code for accessing experimental metadata along wit See the `mouse connectivity section `_ for more details. +What's New - 2.11.3 +----------------------------------------------------------------------- +- Bugfixes related to NWB creation for BehaviorSessions + + What's New - 2.11.2 ----------------------------------------------------------------------- - Fixed mkdir error for non-existing ecephys upload directory