From 9069c182037f85e181aefff277199b67337bed52 Mon Sep 17 00:00:00 2001 From: Cody Baker Date: Fri, 27 Sep 2024 17:25:31 -0400 Subject: [PATCH] update last ones --- docs/conf.py | 2 +- src/nwbinspector/_dandi_inspection.py | 13 +++++++------ src/nwbinspector/_formatting.py | 10 +++++----- src/nwbinspector/_nwbinspector_cli.py | 15 ++++++++++----- src/nwbinspector/_organization.py | 2 +- src/nwbinspector/inspector_tools/__init__.py | 11 +++++++++-- tests/test_inspector.py | 6 +++--- 7 files changed, 36 insertions(+), 23 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 998c66e8d..a551bb704 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -8,7 +8,7 @@ sys.path.append(str(Path(__file__).parent)) from conf_extlinks import extlinks, intersphinx_mapping -sys.path.insert(0, Path(__file__).resolve().parents[1]) +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) project = "NWBInspector" copyright = "2022-2024, CatalystNeuro" diff --git a/src/nwbinspector/_dandi_inspection.py b/src/nwbinspector/_dandi_inspection.py index 360215609..084724ec5 100644 --- a/src/nwbinspector/_dandi_inspection.py +++ b/src/nwbinspector/_dandi_inspection.py @@ -104,7 +104,7 @@ def inspect_dandi_file_path( dandi_file_path: str, dandiset_id: str, dandiset_version: Union[str, Literal["draft"], None] = None, - config: Union[str, pathlib.Path, dict, Literal["dandi"]] = "dandi", + config: Union[str, pathlib.Path, dict, Literal["dandi"], None] = "dandi", checks: Union[list, None] = None, ignore: Union[list[str], None] = None, select: Union[list[str], None] = None, @@ -125,7 +125,7 @@ def inspect_dandi_file_path( The specific published version of the Dandiset to inspect. If None, the latest version is used. If there are no published versions, then 'draft' is used instead. - config : file path, dictionary, or "dandi", default: "dandi" + config : file path, dictionary, "dandi", or None, default: "dandi" If a file path, loads the dictionary configuration from the file. If a dictionary, it must be valid against the configuration schema. If "dandi", uses the requirements for DANDI validation. @@ -178,7 +178,7 @@ def inspect_dandi_file_path( def inspect_url( *, url: str, - config: Union[str, pathlib.Path, dict, Literal["dandi"]] = "dandi", + config: Union[str, pathlib.Path, dict, Literal["dandi"], None] = "dandi", checks: Union[list, None] = None, ignore: Union[list[str], None] = None, select: Union[list[str], None] = None, @@ -196,7 +196,7 @@ def inspect_url( https://dandiarchive.s3.amazonaws.com/blobs/636/57e/63657e32-ad33-4625-b664-31699b5bf664 Note: this must be the `https` URL, not the 's3://' form. - config : file path, dictionary, or "dandi", default: "dandi" + config : file path, dictionary, "dandi", or None, default: "dandi" If a file path, loads the dictionary configuration from the file. If a dictionary, it must be valid against the configuration schema. If "dandi", uses the requirements for DANDI validation. @@ -226,9 +226,10 @@ def inspect_url( filterwarnings(action="ignore", message="No cached namespaces found in .*") filterwarnings(action="ignore", message="Ignoring cached namespace .*") - if not isinstance(config, dict): + if isinstance(config, (str, pathlib.Path)): config = load_config(filepath_or_keyword=config) - validate_config(config=config) + if isinstance(config, dict): + validate_config(config=config) byte_stream = remfile.File(url=url) with ( diff --git a/src/nwbinspector/_formatting.py b/src/nwbinspector/_formatting.py index 554bfafe5..baf147018 100644 --- a/src/nwbinspector/_formatting.py +++ b/src/nwbinspector/_formatting.py @@ -76,14 +76,14 @@ class MessageFormatter: def __init__( self, - messages: list[InspectorMessage], + messages: list[Optional[InspectorMessage]], levels: list[str], reverse: Optional[list[bool]] = None, detailed: bool = False, formatter_options: Optional[FormatterOptions] = None, ) -> None: self.nmessages = len(messages) - self.nfiles = len(set(message.file_path for message in messages)) + self.nfiles = len(set(message.file_path for message in messages)) # type: ignore self.message_count_by_importance = self._count_messages_by_importance(messages=messages) self.initial_organized_messages = organize_messages(messages=messages, levels=levels, reverse=reverse) self.detailed = detailed @@ -108,10 +108,10 @@ def __init__( self.formatted_messages: list = [] @staticmethod - def _count_messages_by_importance(messages: list[InspectorMessage]) -> dict[str, int]: + def _count_messages_by_importance(messages: list[Optional[InspectorMessage]]) -> dict[str, int]: message_count_by_importance = {importance_level.name: 0 for importance_level in Importance} for message in messages: - message_count_by_importance[message.importance.name] += 1 + message_count_by_importance[message.importance.name] += 1 # type: ignore for key in [keys for keys, count in message_count_by_importance.items() if count == 0]: message_count_by_importance.pop(key) return message_count_by_importance @@ -218,7 +218,7 @@ def format_messages(self) -> list[str]: def format_messages( - messages: list[InspectorMessage], + messages: list[Optional[InspectorMessage]], levels: Optional[list[str]] = None, reverse: Optional[list[bool]] = None, detailed: bool = False, diff --git a/src/nwbinspector/_nwbinspector_cli.py b/src/nwbinspector/_nwbinspector_cli.py index 6e9fa5678..db42f5c64 100644 --- a/src/nwbinspector/_nwbinspector_cli.py +++ b/src/nwbinspector/_nwbinspector_cli.py @@ -12,6 +12,7 @@ from ._configuration import load_config from ._dandi_inspection import inspect_dandi_file_path, inspect_dandiset, inspect_url from ._formatting import ( + InspectorOutputJSONEncoder, _get_report_header, format_messages, print_to_console, @@ -89,9 +90,9 @@ def _nwbinspector_cli( path: str, stream: bool = False, version_id: Union[str, None] = None, - report_file_path: str = None, + report_file_path: Union[str, None] = None, config: Union[str, None] = None, - levels: str = None, + levels: Union[str, None] = None, reverse: Union[str, None] = None, overwrite: bool = False, ignore: Union[str, None] = None, @@ -137,16 +138,17 @@ def _nwbinspector_cli( handled_select = select if select is None else select.split(",") handled_importance_threshold = Importance[threshold] show_progress_bar = True if progress_bar is None else strtobool(progress_bar) - modules = [] if modules is None else modules.split(",") + handled_modules = [] if modules is None else modules.split(",") # Trigger the import of custom checks that have been registered and exposed to their respective modules - for module in modules: + for module in handled_modules: importlib.import_module(name=module) # Scan entire Dandiset if stream and ":" not in path: dandiset_id = path dandiset_version = version_id + messages_iterator = inspect_dandiset( dandiset_id=dandiset_id, dandiset_version=dandiset_version, @@ -160,6 +162,8 @@ def _nwbinspector_cli( # Scan a single NWB file in a Dandiset elif stream and ":" in path: dandiset_id, dandi_file_path = path.split(":") + dandiset_version = version_id + messages_iterator = inspect_dandi_file_path( dandi_file_path=dandi_file_path, dandiset_id=dandiset_id, @@ -173,8 +177,9 @@ def _nwbinspector_cli( # Scan single NWB file at URL elif stream and path_is_url: dandi_s3_url = path + messages_iterator = inspect_url( - dandi_s3_url=dandi_s3_url, + url=dandi_s3_url, config=handled_config, ignore=handled_ignore, select=handled_select, diff --git a/src/nwbinspector/_organization.py b/src/nwbinspector/_organization.py index d8176bd62..ed2c4d7fb 100644 --- a/src/nwbinspector/_organization.py +++ b/src/nwbinspector/_organization.py @@ -17,7 +17,7 @@ def _sort_unique_values(unique_values: list, reverse: bool = False) -> list: def organize_messages( - messages: list[InspectorMessage], levels: list[str], reverse: Optional[list[bool]] = None + messages: list[Optional[InspectorMessage]], levels: list[str], reverse: Optional[list[bool]] = None ) -> dict: """ General function for organizing list of InspectorMessages. diff --git a/src/nwbinspector/inspector_tools/__init__.py b/src/nwbinspector/inspector_tools/__init__.py index 134b1f7b6..6cf0e655e 100644 --- a/src/nwbinspector/inspector_tools/__init__.py +++ b/src/nwbinspector/inspector_tools/__init__.py @@ -9,5 +9,12 @@ # Still keep imports functional with warning for soft deprecation cycle # TODO: remove after 9/15/2024 -from .._organization import organize_messages, _get_report_header -from .._formatting import format_message, MessageFormatter, FormatterOptions, print_to_console, save_report +from .._organization import organize_messages +from .._formatting import ( + format_messages, + MessageFormatter, + FormatterOptions, + print_to_console, + save_report, + _get_report_header, +) diff --git a/tests/test_inspector.py b/tests/test_inspector.py index b3d86c916..2d4859692 100644 --- a/tests/test_inspector.py +++ b/tests/test_inspector.py @@ -3,7 +3,7 @@ from pathlib import Path from shutil import rmtree from tempfile import mkdtemp -from typing import Type +from typing import Type, Union from unittest import TestCase import hdmf_zarr @@ -118,7 +118,7 @@ class TestInspectorOnBackend(TestCase): skip_validate = False # TODO: can be removed once NWBZarrIO validation issues are resolved @staticmethod - def assertFileExists(path: FilePathType): + def assertFileExists(path: Union[str, Path]): path = Path(path) assert path.exists() @@ -882,7 +882,7 @@ def test_dandi_config_in_vitro_injection(): assert messages == [] -def test_dandi_config_in_vitro_injection(): +def test_dandi_config_in_vitro_injection_safe(): """Test the safe subject ID retrieval of the in vitro injection.""" nwbfile = make_minimal_nwbfile() nwbfile.subject = Subject(subject_id=None, description="A detailed description about the in vitro setup.")