Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using ruff rule to enforce the existence of docstrings in public methods #1063

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9adc03b
add ruff check for public functions
h-mayorquin Sep 7, 2024
87c6cb5
changelog
h-mayorquin Sep 7, 2024
8623806
work in progress
h-mayorquin Sep 7, 2024
e8a2ccd
work in progress
h-mayorquin Sep 7, 2024
4135939
noqa in proress
h-mayorquin Sep 7, 2024
7afe65e
almost done
h-mayorquin Sep 7, 2024
438913b
DONE
h-mayorquin Sep 7, 2024
3066217
Merge branch 'main' into the_ruffest_rule_of_all
h-mayorquin Sep 10, 2024
f2ef463
Merge branch 'main' into the_ruffest_rule_of_all
h-mayorquin Sep 17, 2024
fb2e484
Merge branch 'main' into the_ruffest_rule_of_all
h-mayorquin Sep 17, 2024
2cd9b55
missing stuff
h-mayorquin Sep 18, 2024
228b32f
first suggestion
h-mayorquin Sep 18, 2024
0d5d6cc
second suggestion
h-mayorquin Sep 18, 2024
8035298
removed
h-mayorquin Sep 18, 2024
c69487b
bruker tiff docstring
h-mayorquin Sep 18, 2024
564703c
bruker tiff single parameters
h-mayorquin Sep 18, 2024
d95364b
miniscope imaging
h-mayorquin Sep 18, 2024
adcf7fb
scanimage
h-mayorquin Sep 18, 2024
9d7f734
suit2p paul suggestion
h-mayorquin Sep 18, 2024
dd85b3c
time intervals
h-mayorquin Sep 18, 2024
1cca391
reverse return in add_to_nwbfile
h-mayorquin Sep 18, 2024
de12b9a
hdmf
h-mayorquin Sep 18, 2024
716d400
Merge branch 'main' into the_ruffest_rule_of_all
h-mayorquin Sep 26, 2024
a770758
remove ruff check for public method docstrings
pauladkisson Nov 21, 2024
e4117e8
removed noqa: D102
pauladkisson Nov 21, 2024
cbfb3a7
removed noqa D102
pauladkisson Nov 21, 2024
be80b61
removed ,D102
pauladkisson Nov 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
# Upcoming

## Deprecations

## Bug Fixes

## Deprecations

## Features
* Using in-house `GenericDataChunkIterator` [PR #1068](https://github.com/catalystneuro/neuroconv/pull/1068)
* Data interfaces now perform source (argument inputs) validation with the json schema [PR #1020](https://github.com/catalystneuro/neuroconv/pull/1020)

## Improvements
* Remove dev test from PR [PR #1092](https://github.com/catalystneuro/neuroconv/pull/1092)
* Run only the most basic testing while a PR is on draft [PR #1082](https://github.com/catalystneuro/neuroconv/pull/1082)
* Using ruff to enforce existence of public functions's docstrings [PR #1062](https://github.com/catalystneuro/neuroconv/pull/1062)
* Test that zarr backend_configuration works in gin data tests [PR #1094](https://github.com/catalystneuro/neuroconv/pull/1094)
* Consolidated weekly workflows into one workflow and added email notifications [PR #1088](https://github.com/catalystneuro/neuroconv/pull/1088)
* Avoid running link test when the PR is on draft [PR #1093](https://github.com/catalystneuro/neuroconv/pull/1093)
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ doctest_optionflags = "ELLIPSIS"

[tool.black]
line-length = 120
target-version = ['py38', 'py39', 'py310']
target-version = ['py39', 'py310']
include = '\.pyi?$'
extend-exclude = '''
/(
Expand All @@ -131,6 +131,7 @@ select = [
"F401", # Unused import
"I", # All isort rules
"D101", # Missing docstring in public class
"D102", # Missing docstring in public method
pauladkisson marked this conversation as resolved.
Show resolved Hide resolved
"D103", # Missing docstring in public function
]
fixable = ["ALL"]
Expand Down
9 changes: 8 additions & 1 deletion src/neuroconv/basedatainterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ class BaseDataInterface(ABC):

@classmethod
def get_source_schema(cls) -> dict:
"""Infer the JSON schema for the source_data from the method signature (annotation typing)."""
"""
Infer the JSON schema for the source_data from the method signature (annotation typing).

Returns
-------
dict
The JSON schema for the source_data.
"""
return get_json_schema_from_method_signature(cls, exclude=["source_data"])

@classmethod
Expand Down
2 changes: 1 addition & 1 deletion src/neuroconv/baseextractorinterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class BaseExtractorInterface(BaseTemporalAlignmentInterface, ABC):
Extractor = None # Class loads dynamically on first call to .get_extractor()

@classmethod
def get_extractor(cls):
def get_extractor(cls): # noqa: D102
if cls.Extractor is not None:
return cls.Extractor
extractor_module = get_package(package_name=cls.ExtractorModuleName)
Expand Down
14 changes: 7 additions & 7 deletions src/neuroconv/datainterfaces/behavior/audio/audiointerface.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def __init__(self, file_paths: list[FilePath], verbose: bool = False):
super().__init__(file_paths=file_paths)
self._segment_starting_times = None

def get_metadata_schema(self) -> dict:
def get_metadata_schema(self) -> dict: # noqa: D102
metadata_schema = super().get_metadata_schema()

time_series_metadata_schema_path = (
Expand All @@ -84,7 +84,7 @@ def get_metadata_schema(self) -> dict:
)
return metadata_schema

def get_metadata(self) -> dict:
def get_metadata(self) -> dict: # noqa: D102
default_name = "AcousticWaveformSeries"
is_multiple_file_path = len(self.source_data["file_paths"]) > 1
audio_metadata = [
Expand All @@ -96,17 +96,17 @@ def get_metadata(self) -> dict:
]
behavior_metadata = dict(Audio=audio_metadata)

metadata = super().get_metadata()
metadata = super().get_metadata() # noqa: D102
metadata.update(Behavior=behavior_metadata)
return metadata

def get_original_timestamps(self) -> np.ndarray:
def get_original_timestamps(self) -> np.ndarray: # noqa: D102
raise NotImplementedError("The AudioInterface does not yet support timestamps.")

def get_timestamps(self) -> Optional[np.ndarray]:
def get_timestamps(self) -> Optional[np.ndarray]: # noqa: D102
raise NotImplementedError("The AudioInterface does not yet support timestamps.")

def set_aligned_timestamps(self, aligned_timestamps: list[np.ndarray]):
def set_aligned_timestamps(self, aligned_timestamps: list[np.ndarray]): # noqa: D102
raise NotImplementedError("The AudioInterface does not yet support timestamps.")

def set_aligned_starting_time(self, aligned_starting_time: float):
Expand Down Expand Up @@ -155,7 +155,7 @@ def set_aligned_segment_starting_times(self, aligned_segment_starting_times: lis

self._segment_starting_times = aligned_segment_starting_times

def align_by_interpolation(self, unaligned_timestamps: np.ndarray, aligned_timestamps: np.ndarray):
def align_by_interpolation(self, unaligned_timestamps: np.ndarray, aligned_timestamps: np.ndarray): # noqa: D102
raise NotImplementedError("The AudioInterface does not yet support timestamps.")

def add_to_nwbfile(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class DeepLabCutInterface(BaseTemporalAlignmentInterface):
_timestamps = None

@classmethod
def get_source_schema(cls) -> dict:
def get_source_schema(cls) -> dict: # noqa: D102
source_schema = super().get_source_schema()
source_schema["properties"]["file_path"]["description"] = "Path to the .h5 file output by dlc."
source_schema["properties"]["config_file_path"]["description"] = "Path to .yml config file"
Expand Down Expand Up @@ -60,7 +60,7 @@ def __init__(
self.verbose = verbose
super().__init__(file_path=file_path, config_file_path=config_file_path)

def get_metadata(self):
def get_metadata(self): # noqa: D102
metadata = super().get_metadata()

if self.config_dict:
Expand All @@ -71,13 +71,13 @@ def get_metadata(self):

return metadata

def get_original_timestamps(self) -> np.ndarray:
def get_original_timestamps(self) -> np.ndarray: # noqa: D102
raise NotImplementedError(
"Unable to retrieve the original unaltered timestamps for this interface! "
"Define the `get_original_timestamps` method for this interface."
)

def get_timestamps(self) -> np.ndarray:
def get_timestamps(self) -> np.ndarray: # noqa: D102
raise NotImplementedError(
"Unable to retrieve timestamps for this interface! Define the `get_timestamps` method for this interface."
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ class FicTracDataInterface(BaseTemporalAlignmentInterface):
}

@classmethod
def get_source_schema(cls) -> dict:
def get_source_schema(cls) -> dict: # noqa: D102
source_schema = super().get_source_schema()
source_schema["properties"]["file_path"]["description"] = "Path to the .dat file (the output of fictrac)"
return source_schema
Expand Down Expand Up @@ -194,7 +194,7 @@ def __init__(
self._timestamps = None
self._starting_time = None

def get_metadata(self):
def get_metadata(self): # noqa: D102
metadata = super().get_metadata()

session_start_time = extract_session_start_time(
Expand Down Expand Up @@ -345,17 +345,17 @@ def get_original_timestamps(self):

return timestamps

def get_timestamps(self):
def get_timestamps(self): # noqa: D102
timestamps = self._timestamps if self._timestamps is not None else self.get_original_timestamps()
if self._starting_time is not None:
timestamps = timestamps + self._starting_time

return timestamps

def set_aligned_timestamps(self, aligned_timestamps):
def set_aligned_timestamps(self, aligned_timestamps): # noqa: D102
self._timestamps = aligned_timestamps

def set_aligned_starting_time(self, aligned_starting_time):
def set_aligned_starting_time(self, aligned_starting_time): # noqa: D102
self._starting_time = aligned_starting_time


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class LightningPoseConverter(NWBConverter):
info = "Interface for handling multiple streams of lightning pose data."

@classmethod
def get_source_schema(cls):
def get_source_schema(cls): # noqa: D102
return get_schema_from_method_signature(cls)

@validate_call
Expand Down Expand Up @@ -70,14 +70,14 @@ def __init__(
self.labeled_video_name = image_series_labeled_video_name or "ImageSeriesLabeledVideo"
self.data_interface_objects.update(dict(LabeledVideo=VideoInterface(file_paths=[labeled_video_file_path])))

def get_conversion_options_schema(self) -> dict:
def get_conversion_options_schema(self) -> dict: # noqa: D102
conversion_options_schema = get_schema_from_method_signature(
method=self.add_to_nwbfile, exclude=["nwbfile", "metadata"]
)

return conversion_options_schema

def get_metadata(self) -> DeepDict:
def get_metadata(self) -> DeepDict: # noqa: D102
metadata = self.data_interface_objects["PoseEstimation"].get_metadata()
original_video_interface = self.data_interface_objects["OriginalVideo"]
original_videos_metadata = original_video_interface.get_metadata()
Expand Down Expand Up @@ -111,6 +111,28 @@ def add_to_nwbfile(
starting_frames_labeled_videos: Optional[list[int]] = None,
stub_test: bool = False,
):
"""
Add behavior and pose estimation data, including original and labeled videos, to the specified NWBFile.

Parameters
----------
nwbfile : NWBFile
The NWBFile object to which the data will be added.
metadata : dict
Metadata dictionary containing information about the behavior and videos.
reference_frame : str, optional
Description of the reference frame for pose estimation, by default None.
confidence_definition : str, optional
Definition for the confidence levels in pose estimation, by default None.
external_mode : bool, optional
If True, the videos will be referenced externally rather than embedded within the NWB file, by default True.
starting_frames_original_videos : list of int, optional
List of starting frames for the original videos, by default None.
starting_frames_labeled_videos : list of int, optional
List of starting frames for the labeled videos, by default None.
stub_test : bool, optional
If True, only a subset of the data will be added for testing purposes, by default False.
"""
original_video_interface = self.data_interface_objects["OriginalVideo"]

original_video_metadata = next(
Expand Down Expand Up @@ -172,6 +194,33 @@ def run_conversion(
starting_frames_labeled_videos: Optional[list] = None,
stub_test: bool = False,
) -> None:
"""
Run the full conversion process, adding behavior, video, and pose estimation data to an NWB file.

Parameters
----------
nwbfile_path : FilePath, optional
The file path where the NWB file will be saved. If None, the file is handled in memory.
nwbfile : NWBFile, optional
An in-memory NWBFile object. If None, a new NWBFile object will be created.
metadata : dict, optional
Metadata dictionary for describing the NWB file contents. If None, it is auto-generated.
overwrite : bool, optional
If True, overwrites the NWB file at `nwbfile_path` if it exists. If False, appends to the file, by default False.
reference_frame : str, optional
Description of the reference frame for pose estimation, by default None.
confidence_definition : str, optional
Definition for confidence levels in pose estimation, by default None.
external_mode : bool, optional
If True, the videos will be referenced externally rather than embedded within the NWB file, by default True.
starting_frames_original_videos : list of int, optional
List of starting frames for the original videos, by default None.
starting_frames_labeled_videos : list of int, optional
List of starting frames for the labeled videos, by default None.
stub_test : bool, optional
If True, only a subset of the data will be added for testing purposes, by default False.

"""
if metadata is None:
metadata = self.get_metadata()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class LightningPoseDataInterface(BaseTemporalAlignmentInterface):
associated_suffixes = (".csv", ".mp4")
info = "Interface for handling a single stream of lightning pose data."

def get_metadata_schema(self) -> dict:
def get_metadata_schema(self) -> dict: # noqa: D102
metadata_schema = super().get_metadata_schema()
metadata_schema["properties"]["Behavior"] = get_base_schema(tag="Behavior")

Expand Down Expand Up @@ -123,24 +123,24 @@ def _get_original_video_shape(self) -> tuple[int, int]:
# image size of the original video is in height x width
return video_shape[0], video_shape[1]

def get_original_timestamps(self, stub_test: bool = False) -> np.ndarray:
def get_original_timestamps(self, stub_test: bool = False) -> np.ndarray: # noqa: D102
max_frames = 10 if stub_test else None
with self._vc(file_path=str(self.original_video_file_path)) as video:
timestamps = video.get_video_timestamps(max_frames=max_frames)
return timestamps

def get_timestamps(self, stub_test: bool = False) -> np.ndarray:
def get_timestamps(self, stub_test: bool = False) -> np.ndarray: # noqa: D102
max_frames = 10 if stub_test else None
if self._times is None:
return self.get_original_timestamps(stub_test=stub_test)

timestamps = self._times if not stub_test else self._times[:max_frames]
return timestamps

def set_aligned_timestamps(self, aligned_timestamps: np.ndarray):
def set_aligned_timestamps(self, aligned_timestamps: np.ndarray): # noqa: D102
self._times = aligned_timestamps

def get_metadata(self) -> DeepDict:
def get_metadata(self) -> DeepDict: # noqa: D102
metadata = super().get_metadata()

# Update the session start time if folder structure is saved in the format: YYYY-MM-DD/HH-MM-SS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def __init__(
)
self.timestamps_dict = {}

def get_metadata(self) -> DeepDict:
def get_metadata(self) -> DeepDict: # noqa: D102
metadata = super().get_metadata()
session_dict = read_medpc_file(
file_path=self.source_data["file_path"],
Expand All @@ -98,7 +98,7 @@ def get_metadata(self) -> DeepDict:

return metadata

def get_metadata_schema(self) -> dict:
def get_metadata_schema(self) -> dict: # noqa: D102
metadata_schema = super().get_metadata_schema()
medpc_name_to_info_dict = self.source_data["metadata_medpc_name_to_info_dict"]
metadata_schema["properties"]["MedPC"] = {
Expand Down Expand Up @@ -178,11 +178,12 @@ def set_aligned_starting_time(self, aligned_starting_time: float, medpc_name_to_
aligned_timestamps_dict[name] = original_timestamps + aligned_starting_time
self.set_aligned_timestamps(aligned_timestamps_dict=aligned_timestamps_dict)

def add_to_nwbfile(
def add_to_nwbfile( # noqa: D102
self,
nwbfile: NWBFile,
metadata: dict,
) -> None:

ndx_events = get_package(package_name="ndx_events", installation_instructions="pip install ndx-events")
medpc_name_to_info_dict = metadata["MedPC"].get("medpc_name_to_info_dict", None)
assert medpc_name_to_info_dict is not None, "medpc_name_to_info_dict must be provided in metadata"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class MiniscopeBehaviorInterface(BaseDataInterface):
info = "Interface for Miniscope behavior video data."

@classmethod
def get_source_schema(cls) -> dict:
def get_source_schema(cls) -> dict: # noqa: D102
source_schema = super().get_source_schema()
source_schema["properties"]["folder_path"][
"description"
Expand Down Expand Up @@ -66,7 +66,7 @@ def __init__(self, folder_path: DirectoryPath):
assert len(self._starting_frames) == len(self._behav_avi_file_paths)
self._timestamps = get_timestamps(folder_path=str(folder_path), file_pattern="BehavCam*/timeStamps.csv")

def get_metadata(self) -> DeepDict:
def get_metadata(self) -> DeepDict: # noqa: D102
metadata = super().get_metadata()
metadata["NWBFile"].update(session_start_time=self._recording_start_times[0])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,21 @@ def __init__(self, file_path: FilePath, verbose: bool = True):

super().__init__(file_path=file_path)

def get_original_timestamps(self) -> np.ndarray:
def get_original_timestamps(self) -> np.ndarray: # noqa: D102
data = read_data(self.file_path)

times = data["TimeStamp"] / 1000000 # Neuralynx stores times in microseconds
times = times - times[0]

return times

def get_timestamps(self) -> np.ndarray:
def get_timestamps(self) -> np.ndarray: # noqa: D102
return self._timestamps

def set_aligned_timestamps(self, aligned_timestamps: np.ndarray) -> None:
def set_aligned_timestamps(self, aligned_timestamps: np.ndarray) -> None: # noqa: D102
self._timestamps = aligned_timestamps

def get_metadata(self) -> DeepDict:
def get_metadata(self) -> DeepDict: # noqa: D102
metadata = super().get_metadata()

metadata["NWBFile"].update(session_start_time=self.header["TimeCreated"])
Expand All @@ -67,7 +67,7 @@ def get_metadata(self) -> DeepDict:
)
return metadata

def get_metadata_schema(self) -> dict:
def get_metadata_schema(self) -> dict: # noqa: D102
metadata_schema = super().get_metadata_schema()

if "Behavior" not in metadata_schema["properties"]:
Expand Down
Loading
Loading