From 3e5043c8fb38ef778c15ad26b31b6ce42f15743d Mon Sep 17 00:00:00 2001 From: David Stansby Date: Tue, 21 Feb 2023 11:21:11 +0000 Subject: [PATCH] Use standard pre-commit config (#69) * Add standard pre-commit config * Automated pre-commit fixes * Make ruff happy * Make mypy happy * Fix setup.py line length --- .pre-commit-config.yaml | 20 ++++++------- brainreg_segment/atlas/utils.py | 7 +++-- brainreg_segment/layout/gui_elements.py | 9 ++++-- brainreg_segment/measurement/measurement.py | 23 ++++++++++----- brainreg_segment/segment.py | 20 ++++++++----- .../segmentation_panels/regions.py | 27 +++++++++++------ .../segmentation_panels/tracks.py | 27 +++++++++++------ pyproject.toml | 29 ++++--------------- setup.cfg | 4 +-- setup.py | 5 +++- .../test_tracks/test_track_analysis.py | 2 +- .../test_unit/test_atlas/test_atlas_utils.py | 2 +- 12 files changed, 98 insertions(+), 77 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 061f327..0dfba3b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,8 +1,4 @@ repos: - - repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: @@ -15,14 +11,18 @@ repos: args: [--fix=lf] - id: requirements-txt-fixer - id: trailing-whitespace - # bump2version produces whitespace in setup.cfg, so exclude to - # not inferfere with versioning - exclude: setup.cfg - - repo: https://github.com/pycqa/flake8 - rev: 6.0.0 + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.240 hooks: - - id: flake8 + - id: ruff - repo: https://github.com/psf/black rev: 23.1.0 hooks: - id: black + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v0.991 + hooks: + - id: mypy + additional_dependencies: + - types-setuptools + - types-requests diff --git a/brainreg_segment/atlas/utils.py b/brainreg_segment/atlas/utils.py index e08d50d..96f26f1 100644 --- a/brainreg_segment/atlas/utils.py +++ b/brainreg_segment/atlas/utils.py @@ -75,9 +75,10 @@ def structure_from_viewer(status, atlas_layer, atlas): # Using a regex, extract list of coordinates from status string assert hasattr(atlas_layer, "data"), "Atlas layer appears to be empty" - assert ( - atlas_layer.data.ndim == 3 - ), f'Atlas layer data does not have the right dim ("{atlas_layer.data.ndim}")' + assert atlas_layer.data.ndim == 3, ( + "Atlas layer data does not have the right dim " + f'("{atlas_layer.data.ndim}")' + ) try: coords = re.findall(r"\[\d{1,5}\s+\d{1,5}\s+\d{1,5}\]", status)[0][ diff --git a/brainreg_segment/layout/gui_elements.py b/brainreg_segment/layout/gui_elements.py index 510fd1d..6512e6d 100644 --- a/brainreg_segment/layout/gui_elements.py +++ b/brainreg_segment/layout/gui_elements.py @@ -1,5 +1,6 @@ # GUI ELEMENTS -# from napari.resources import build_icons # Contains .SVGPATH to all icons for napari +# from napari.resources import build_icons # Contains .SVGPATH to all icons +# for napari from qtpy.QtWidgets import ( QCheckBox, @@ -91,7 +92,8 @@ def add_button( # "QRadioButton { text-align: right; padding: 0; spacing: 30px;}" # ) -# # Too change indicator button ... needs to dynamically retrieve icon from Napari. +# # Too change indicator button ... needs to dynamically retrieve icon +# # from Napari. # # Icons are saved as .svg files under napari.resources SVGPATH # # "QRadioButton::indicator" # # "{" @@ -104,7 +106,8 @@ def add_button( # # "}" # # "QRadioButton::indicator::checked" # # "{" -# # "image: url(/opt/miniconda3/envs/analysis/lib/python3.6/site-packages/napari/resources/icons/visibility.svg);" +# # "image: url(/opt/miniconda3/envs/analysis/lib/python3.6/site-packages/ +# napari/resources/icons/visibility.svg);" # # "}" # # ) diff --git a/brainreg_segment/measurement/measurement.py b/brainreg_segment/measurement/measurement.py index 0001256..349ab58 100644 --- a/brainreg_segment/measurement/measurement.py +++ b/brainreg_segment/measurement/measurement.py @@ -13,7 +13,7 @@ # (anteroposterior, mediolateral, vectical) def get_angles_and_distances_between_consecutive_points( point_layer: "napari.layers.Points", -) -> Tuple[List[float]]: +) -> Tuple[List[float], List[float], List[float]]: """Returns the distance and angles for each pair of consecutive points. Receives a points layer and for each pair of consecutive points it @@ -45,13 +45,15 @@ def get_angles_and_distances_between_consecutive_points( # projecting the vector in the sagital plane is just removing # the "y/mediolateral" coordinate segment_vector_zx = segment_vector[[2, 0]] - # for the angle, z is used as the first direction/axis and x as the other + # for the angle, z is used as the first direction/axis and x as the + # other ap_angle = math.atan2(segment_vector_zx[1], segment_vector_zx[0]) ap_angles.append(ap_angle) # projecting the vector in the frontal plane is just removing # the anterioposterior coordinate. segment_vector_zy = segment_vector[[2, 1]] - # for the angle, z is used as the first direction/axis and y as the other + # for the angle, z is used as the first direction/axis and y as the + # other mp_angle = math.atan2(segment_vector_zy[1], segment_vector_zy[0]) mp_angles.append(mp_angle) distances.append(np.linalg.norm(segment_vector)) @@ -100,9 +102,12 @@ def get_vectors_joining_points( def analyze_points_layer( point_layer: "napari.layers.Points", save_resuts_to_output_folder: bool = False, - output_folder: pathlib.Path = "results_folder", + output_folder: pathlib.Path = pathlib.Path("results_folder"), ) -> List[napari.types.LayerDataTuple]: - """Analyzes a point layer and saves distances and angles for consecutive points + """ + Analyzes a point layer and saves distances and angles for consecutive + points + points.csv id, coordx,  coordy,  coordz 0, .. @@ -119,7 +124,8 @@ def analyze_points_layer( point_layer: A points layer to analyze. save_resuts_to_output_folder: A boolean, whether to save the results to the output folder below. If False, output_folder is ignored. - output_folder: Name of the folder where the output is going to be saved. + output_folder: Name of the folder where the output is going to be + saved. """ if save_resuts_to_output_folder and not os.path.exists(output_folder): os.mkdir(output_folder) @@ -171,7 +177,10 @@ def analyze_points_layer( # Adding vectors as a shapes layer. vectors_text = { - "text": "distance: {distance:.4f}\nap_angle: {ap_angle:.4f}\n mp_angle: {mp_angle:.4f}", + "text": ( + "distance: {distance:.4f}\nap_angle: {ap_angle:.4f}\n" + "mp_angle: {mp_angle:.4f}" + ), "size": 8, "color": "green", "anchor": "upper_left", diff --git a/brainreg_segment/segment.py b/brainreg_segment/segment.py index b22d2eb..f1968cc 100644 --- a/brainreg_segment/segment.py +++ b/brainreg_segment/segment.py @@ -1,12 +1,13 @@ from pathlib import Path +from typing import List, Optional import napari import numpy as np +from bg_atlasapi import BrainGlobeAtlas from napari.qt.threading import thread_worker from qtpy import QtCore from qtpy.QtWidgets import QFileDialog, QGridLayout, QGroupBox, QLabel, QWidget -from bg_atlasapi import BrainGlobeAtlas from brainreg_segment.atlas.utils import ( get_available_atlases, structure_from_viewer, @@ -26,12 +27,12 @@ from brainreg_segment.paths import Paths from brainreg_segment.regions.IO import export_label_layers, save_label_layers -# SEGMENTATION ################################################################################ +### SEGMENTATION from brainreg_segment.segmentation_panels.regions import RegionSeg from brainreg_segment.segmentation_panels.tracks import TrackSeg from brainreg_segment.tracks.IO import export_splines, save_track_layers -# LAYOUT HELPERS ################################################################################ +### LAYOUT HELPERS class SegmentationWidget(QWidget): @@ -46,17 +47,20 @@ def __init__( self.viewer = viewer # Main layers - self.base_layer = [] # Contains registered brain / reference brain - self.atlas_layer = [] # Contains annotations / region information + + # Contains registered brain / reference brain + self.base_layer: Optional[napari.layers.Image] = None + # Contains annotations / region information + self.atlas_layer: Optional[napari.layers.Labels] = None # Other data - self.hemispheres_data = [] + self.hemispheres_data: Optional[np.ndarray] = None # Track variables - self.track_layers = [] + self.track_layers: List[napari.layers.Tracks] = [] # Region variables - self.label_layers = [] + self.label_layers: List[napari.layers.Labels] = [] # Atlas variables self.current_atlas_name = "" diff --git a/brainreg_segment/segmentation_panels/regions.py b/brainreg_segment/segmentation_panels/regions.py index 7501b08..35b95df 100644 --- a/brainreg_segment/segmentation_panels/regions.py +++ b/brainreg_segment/segmentation_panels/regions.py @@ -89,31 +89,40 @@ def add_region_panel(self, row): def toggle_region_panel(self): # TODO: Change color scheme directly when theme is switched - # TODO: "text-align" property should follow constant SEGM_METHODS_PANEL_ALIGN + # TODO: "text-align" property should follow constant + # SEGM_METHODS_PANEL_ALIGN if self.region_panel.isVisible(): self.region_panel.setVisible(False) if self.parent.viewer.theme == "dark": self.parent.show_regionseg_button.setStyleSheet( - f"QPushButton {{ background-color: #414851; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" - f"QPushButton:pressed {{ background-color: #414851; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton {{ background-color: #414851; text-align:" + f"{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton:pressed {{ background-color: #414851; " + f"text-align:{SEGM_METHODS_PANEL_ALIGN};}}" ) else: self.parent.show_regionseg_button.setStyleSheet( - f"QPushButton {{ background-color: #d6d0ce; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" - f"QPushButton:pressed {{ background-color: #d6d0ce; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton {{ background-color: #d6d0ce; text-align:" + f"{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton:pressed {{ background-color: #d6d0ce; " + f"text-align:{SEGM_METHODS_PANEL_ALIGN};}}" ) else: self.region_panel.setVisible(True) if self.parent.viewer.theme == "dark": self.parent.show_regionseg_button.setStyleSheet( - f"QPushButton {{ background-color: #7e868f; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" - f"QPushButton:pressed {{ background-color: #7e868f; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton {{ background-color: #7e868f; text-align:" + f"{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton:pressed {{ background-color: #7e868f; " + f"text-align:{SEGM_METHODS_PANEL_ALIGN};}}" ) else: self.parent.show_regionseg_button.setStyleSheet( - f"QPushButton {{ background-color: #fdf194; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" - f"QPushButton:pressed {{ background-color: #fdf194; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton {{ background-color: #fdf194; text-align:" + f"{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton:pressed {{ background-color: #fdf194; " + f"text-align:{SEGM_METHODS_PANEL_ALIGN};}}" ) def check_saved_region(self): diff --git a/brainreg_segment/segmentation_panels/tracks.py b/brainreg_segment/segmentation_panels/tracks.py index 119a3cc..71c663e 100644 --- a/brainreg_segment/segmentation_panels/tracks.py +++ b/brainreg_segment/segmentation_panels/tracks.py @@ -139,31 +139,40 @@ def add_track_panel(self, row): def toggle_track_panel(self): # TODO: Change color scheme directly when theme is switched - # TODO: "text-align" property should follow constant SEGM_METHODS_PANEL_ALIGN + # TODO: "text-align" property should follow constant + # SEGM_METHODS_PANEL_ALIGN if self.track_panel.isVisible(): self.track_panel.setVisible(False) if self.parent.viewer.theme == "dark": self.parent.show_trackseg_button.setStyleSheet( - f"QPushButton {{ background-color: #414851; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" - f"QPushButton:pressed {{ background-color: #414851; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton {{ background-color: #414851; text-align:" + f"{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton:pressed {{ background-color: #414851; " + f"text-align:{SEGM_METHODS_PANEL_ALIGN};}}" ) else: self.parent.show_trackseg_button.setStyleSheet( - f"QPushButton {{ background-color: #d6d0ce; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" - f"QPushButton:pressed {{ background-color: #d6d0ce; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton {{ background-color: #d6d0ce; text-align:" + f"{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton:pressed {{ background-color: #d6d0ce; " + f"text-align:{SEGM_METHODS_PANEL_ALIGN};}}" ) else: self.track_panel.setVisible(True) if self.parent.viewer.theme == "dark": self.parent.show_trackseg_button.setStyleSheet( - f"QPushButton {{ background-color: #7e868f; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" - f"QPushButton:pressed {{ background-color: #7e868f; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton {{ background-color: #7e868f; text-align:" + f"{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton:pressed {{ background-color: #7e868f; " + f"text-align:{SEGM_METHODS_PANEL_ALIGN};}}" ) else: self.parent.show_trackseg_button.setStyleSheet( - f"QPushButton {{ background-color: #fdf194; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" - f"QPushButton:pressed {{ background-color: #fdf194; text-align:{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton {{ background-color: #fdf194; text-align:" + f"{SEGM_METHODS_PANEL_ALIGN};}}" + f"QPushButton:pressed {{ background-color: #fdf194; " + f"text-align:{SEGM_METHODS_PANEL_ALIGN};}}" ) def check_saved_track(self): diff --git a/pyproject.toml b/pyproject.toml index 9e9b6f6..4e758eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,27 +1,10 @@ [tool.black] -target-version = ['py36', 'py37', 'py38'] +target-version = ['py38', 'py39', 'py310'] skip-string-normalization = false line-length = 79 -exclude = ''' -( - /( - \.eggs - | \.git - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist - | examples - )/ -) -''' -[tool.isort] -profile = "black" -line_length = 79 -sections=["FUTURE","STDLIB","THIRDPARTY","BRAINGLOBE","FIRSTPARTY","LOCALFOLDER"] -known_brainglobe=["brainreg", "brainreg_segment", "brainglobe_napari_io", "bg_space", "bg_atlasapi"] +[tool.ruff] +line-length = 79 +exclude = ["__init__.py","build",".eggs"] +select = ["I", "E", "F"] +fix = true diff --git a/setup.cfg b/setup.cfg index 1558c58..492f7e5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,14 +4,14 @@ commit = True tag = True tag_name = {new_version} parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+)(?P\d+))? -serialize = +serialize = {major}.{minor}.{patch}-{release}{rc} {major}.{minor}.{patch} [bumpversion:part:release] optional_value = prod first_value = rc -values = +values = rc prod diff --git a/setup.py b/setup.py index 8b7424d..9a6f0b9 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,10 @@ author="Adam Tyson, Horst Obenhaus", author_email="code@adamltyson.com", license="BSD-3-Clause", - description="Manual segmentation of 3D brain structures in a common anatomical space", + description=( + "Manual segmentation of 3D brain structures " + "in a common anatomical space" + ), long_description=long_description, long_description_content_type="text/markdown", install_requires=requirements, diff --git a/tests/tests/test_integration/test_tracks/test_track_analysis.py b/tests/tests/test_integration/test_tracks/test_track_analysis.py index 556d376..7d5e322 100644 --- a/tests/tests/test_integration/test_tracks/test_track_analysis.py +++ b/tests/tests/test_integration/test_tracks/test_track_analysis.py @@ -2,8 +2,8 @@ import numpy as np import pandas as pd - from bg_atlasapi import BrainGlobeAtlas + from brainreg_segment.tracks.analysis import run_track_analysis atlas_name = "allen_mouse_50um" diff --git a/tests/tests/test_unit/test_atlas/test_atlas_utils.py b/tests/tests/test_unit/test_atlas/test_atlas_utils.py index e338a8b..77aa882 100644 --- a/tests/tests/test_unit/test_atlas/test_atlas_utils.py +++ b/tests/tests/test_unit/test_atlas/test_atlas_utils.py @@ -1,6 +1,6 @@ import numpy as np - from bg_atlasapi import BrainGlobeAtlas + from brainreg_segment.atlas import utils as atlas_utils atlas_name = "allen_mouse_50um"