Skip to content

Commit

Permalink
chore: Drop python 3.8 (#1206)
Browse files Browse the repository at this point in the history
Python 3.8 reached EOL so it is time to drop it.

## Summary by Sourcery

Drop support for Python 3.8 across the codebase and CI configuration.
Update type annotations to use modern Python syntax and refactor code
for improved readability and consistency.

Enhancements:
- Update type annotations to use Python 3.9+ syntax, replacing
typing.List and typing.Dict with list and dict.
- Refactor test cases to use updated type annotations and improve
readability.
- Refactor code to use context managers with parentheses for better
readability and consistency.

CI:
- Remove Python 3.8 from the CI configuration as it has reached
end-of-life.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Updated Python version support for testing workflows to include
versions 3.9 to 3.12.
- Updated napari versions in testing configurations to the latest
releases.

- **Bug Fixes**
- Corrected inconsistencies in method signatures and type annotations
throughout the codebase.

- **Chores**
- Removed deprecated Python 3.8 references from testing workflows and
configuration files.
- Eliminated constraints files for Python 3.8 to streamline dependency
management.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
Czaki authored Oct 17, 2024
1 parent 24978a5 commit 6d348fc
Show file tree
Hide file tree
Showing 97 changed files with 532 additions and 1,599 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/test_napari_widgets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
with:
python_version: "3.10"
os: ${{ matrix.os }}
napari: "napari5"
napari: "napari54"
qt_backend: ${{ matrix.qt_backend }}
timeout: 10

Expand All @@ -36,10 +36,10 @@ jobs:
strategy:
fail-fast: false
matrix:
napari: ["napari417", "napari418"]
napari: ["napari419", "napari54"]
qt_backend: ["PyQt5"]
include:
- napari: "napari417"
- napari: "napari54"
qt_backend: "PySide2"
if: github.event_name == 'push'
uses: ./.github/workflows/base_test_workflow.yml
Expand Down
30 changes: 15 additions & 15 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,24 +50,24 @@ jobs:
strategy:
fail-fast: false
matrix:
python_version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python_version: ["3.9", "3.10", "3.11", "3.12"]
os: ["ubuntu-20.04"]
qt_backend: ["PyQt5"]
tox_args: [ "" ]
include:
- python_version: "3.9"
- python_version: "3.11"
os: "macos-13"
qt_backend: "PyQt5"
- python_version: "3.9"
- python_version: "3.11"
os: "windows-2019"
qt_backend: "PyQt5"
- python_version: "3.9"
- python_version: "3.10"
os: "ubuntu-20.04"
qt_backend: "PySide2"
- python_version: "3.9"
- python_version: "3.10"
os: "ubuntu-22.04"
qt_backend: "PySide6"
- python_version: "3.10"
- python_version: "3.12"
os: "ubuntu-22.04"
qt_backend: "PyQt6"
- python_version: "3.10"
Expand All @@ -90,20 +90,20 @@ jobs:
strategy:
fail-fast: false
matrix:
python_version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python_version: ["3.9", "3.10", "3.11", "3.12"]
os: ["ubuntu-20.04", "macos-13", "windows-2019"]
qt_backend: ["PySide2", "PyQt5"]
include:
- python_version: "3.11"
- python_version: "3.12"
qt_backend: "PyQt5"
os: "ubuntu-22.04"
- python_version: "3.9"
- python_version: "3.10"
os: "ubuntu-22.04"
qt_backend: "PySide6"
- python_version: "3.9"
- python_version: "3.11"
os: "ubuntu-22.04"
qt_backend: "PyQt6"
- python_version: "3.10"
- python_version: "3.11"
os: "ubuntu-22.04"
qt_backend: "PyQt5"
pydantic: "_pydantic_1"
Expand All @@ -124,8 +124,8 @@ jobs:
uses: ./.github/workflows/base_test_workflow.yml
with:
test_data: True
python_version: "3.10"
tox_args: "-e py310-PyQt5-coverage"
python_version: "3.12"
tox_args: "-e py312-PyQt5-coverage"
coverage: true

test_minimal:
Expand All @@ -134,8 +134,8 @@ jobs:
uses: ./.github/workflows/base_test_workflow.yml
with:
test_data: True
python_version: "3.8"
tox_args: "-e py38-PyQt5-minimal"
python_version: "3.9"
tox_args: "-e py39-PyQt5-minimal"
coverage: true

coverage_prepare:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/upgrade-dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
pip install -U uv
flags=(--extra pyqt6 --extra pyside2 --extra pyside6 --extra test --extra pyinstaller_base)
for pyv in 3.8 3.9 3.10 3.11 3.12; do
for pyv in 3.9 3.10 3.11 3.12; do
uv pip compile --python-version ${pyv} --upgrade --output-file requirements/constraints_py${pyv}.txt pyproject.toml requirements/version_denylist.txt "${flags[@]}"
uv pip compile --python-version ${pyv} --upgrade --output-file requirements/constraints_py${pyv}_pydantic_1.txt pyproject.toml requirements/version_denylist.txt "${flags[@]}" --constraint requirements/pydantic_1.txt
done
Expand Down
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ stages:
displayName: "download data"
- task: UsePythonVersion@0
inputs:
versionSpec: '3.9'
versionSpec: '3.11'
displayName: 'Use Python $(python.version)'
- script: python build_utils/cut_changelog.py changelog_cut.md
displayName: "Cut changelog"
Expand Down
5 changes: 3 additions & 2 deletions package/PartSeg/_launcher/check_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ def run(self):
return
try:
if os.path.exists(os.path.join(state_store.save_folder, IGNORE_FILE)):
with open(os.path.join(state_store.save_folder, IGNORE_FILE), encoding="utf-8") as f_p, suppress(
ValueError
with (
open(os.path.join(state_store.save_folder, IGNORE_FILE), encoding="utf-8") as f_p,
suppress(ValueError),
):
old_date = date.fromisoformat(f_p.read())
if (date.today() - old_date).days < IGNORE_DAYS:
Expand Down
4 changes: 2 additions & 2 deletions package/PartSeg/_launcher/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os
import warnings
from functools import partial
from typing import TYPE_CHECKING, Type
from typing import TYPE_CHECKING

from qtpy.QtCore import QSize, Qt, QThread, Signal
from qtpy.QtGui import QIcon
Expand Down Expand Up @@ -34,7 +34,7 @@ def run(self):

plugins.register()
main_window_module = importlib.import_module(self.module)
main_window: Type[BaseMainWindow] = main_window_module.MainWindow
main_window: type[BaseMainWindow] = main_window_module.MainWindow
settings: BaseSettings = main_window.get_setting_class()(main_window_module.CONFIG_FOLDER)
self.errors = settings.load()
reader = TiffImageReader()
Expand Down
8 changes: 4 additions & 4 deletions package/PartSeg/_roi_analysis/advanced_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os
from contextlib import suppress
from copy import deepcopy
from typing import List, Optional, Tuple, Type, Union, cast
from typing import Optional, Union, cast

from qtpy.QtCore import QEvent, Qt, Slot
from qtpy.QtGui import QIcon
Expand Down Expand Up @@ -49,7 +49,7 @@
from PartSegCore.universal_const import UNIT_SCALE, Units
from PartSegData import icons_dir

_DialogType = Union[Type[str], Type[int], Type[float]]
_DialogType = Union[type[str], type[int], type[float]]


def h_line():
Expand Down Expand Up @@ -366,7 +366,7 @@ class MeasurementSettings(QWidget):
def __init__(self, settings: PartSettings, parent=None): # noqa: PLR0915
super().__init__(parent)
self.chosen_element: Optional[MeasurementListWidgetItem] = None
self.chosen_element_area: Optional[Tuple[AreaType, float]] = None
self.chosen_element_area: Optional[tuple[AreaType, float]] = None
self.settings = settings
self.profile_list = QListWidget(self)
self.profile_description = QTextEdit(self)
Expand Down Expand Up @@ -841,7 +841,7 @@ def __init__(
self,
text: str,
help_text: str = "",
objects_list: Optional[List[Union[Tuple[str, _DialogType], Tuple[str, _DialogType, str]]]] = None,
objects_list: Optional[list[Union[tuple[str, _DialogType], tuple[str, _DialogType, str]]]] = None,
parent: Optional[QWidget] = None,
):
if objects_list is None: # pragma: no cover
Expand Down
4 changes: 2 additions & 2 deletions package/PartSeg/_roi_analysis/batch_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def get_name(cls) -> str:
return "Excel (*.xlsx)"

@classmethod
def get_fields(cls) -> typing.List[typing.Union[AlgorithmProperty, str]]:
def get_fields(cls) -> list[typing.Union[AlgorithmProperty, str]]:
return []


Expand Down Expand Up @@ -376,7 +376,7 @@ class CalculationPrepare(QDialog):

def __init__(
self,
file_list: typing.List[os.PathLike],
file_list: list[os.PathLike],
calculation_plan: CalculationPlan,
measurement_file_path: os.PathLike,
settings: PartSettings,
Expand Down
2 changes: 1 addition & 1 deletion package/PartSeg/_roi_analysis/export_batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def _excel_path_changed(self):

def _extract_information_from_excel_to_export(
excel_path: typing.Union[str, Path], base_folder: typing.Union[str, Path]
) -> typing.List[typing.Tuple[str, bool]]:
) -> list[tuple[str, bool]]:
"""Extract information from Excel file to export"""
file_list = []
file_set = set()
Expand Down
3 changes: 1 addition & 2 deletions package/PartSeg/_roi_analysis/main_window.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import os
from contextlib import suppress
from typing import Type

from qtpy.QtCore import QByteArray, Qt
from qtpy.QtGui import QIcon, QKeyEvent, QKeySequence, QResizeEvent
Expand Down Expand Up @@ -534,7 +533,7 @@ class MainWindow(BaseMainWindow):
settings: PartSettings

@classmethod
def get_setting_class(cls) -> Type[PartSettings]:
def get_setting_class(cls) -> type[PartSettings]:
return PartSettings

initial_image_path = PartSegData.segmentation_analysis_default_image
Expand Down
9 changes: 4 additions & 5 deletions package/PartSeg/_roi_analysis/measurement_widget.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import locale
import os
from enum import Enum
from typing import List, Tuple

from qtpy.QtCore import Qt
from qtpy.QtGui import QKeyEvent, QResizeEvent
Expand Down Expand Up @@ -56,7 +55,7 @@ def clear(self):
self.header = []
self.max_rows = 0
self.content = []
self.measurements: List[MeasurementResult] = []
self.measurements: list[MeasurementResult] = []

def get_size(self, save_orientation: bool):
if save_orientation:
Expand Down Expand Up @@ -116,13 +115,13 @@ def get_val_as_str(self, x: int, y: int, save_orientation: bool) -> str:
val = sublist[y]
return locale.str(val) if isinstance(val, float) else str(val)

def get_header(self, save_orientation: bool) -> List[str]:
def get_header(self, save_orientation: bool) -> list[str]:
if save_orientation:
return [str(i) for i in range(self.max_rows)]

return self.header

def get_rows(self, save_orientation: bool) -> List[str]:
def get_rows(self, save_orientation: bool) -> list[str]:
return self.get_header(not save_orientation)


Expand Down Expand Up @@ -315,7 +314,7 @@ def update_measurement_list(self):
self.measurement_type.blockSignals(False)

@staticmethod
def _move_widgets(widgets_list: List[Tuple[QWidget, int]], layout1: QBoxLayout, layout2: QBoxLayout):
def _move_widgets(widgets_list: list[tuple[QWidget, int]], layout1: QBoxLayout, layout2: QBoxLayout):
for el in widgets_list:
layout1.removeWidget(el[0])
layout2.addWidget(el[0], el[1])
Expand Down
16 changes: 8 additions & 8 deletions package/PartSeg/_roi_analysis/partseg_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class PartSettings(BaseSettings):
json_encoder_class = PartSegEncoder
load_metadata = staticmethod(load_metadata)
last_executed_algorithm: str
save_locations_keys: typing.ClassVar[typing.List[str]] = [
save_locations_keys: typing.ClassVar[list[str]] = [
"open_directory",
"save_directory",
"export_directory",
Expand Down Expand Up @@ -132,7 +132,7 @@ def set_project_info(self, data: typing.Union[ProjectTuple, MaskInfo, PointsInfo
)
self.algorithm_changed.emit()

def get_save_list(self) -> typing.List[SaveSettingsDescription]:
def get_save_list(self) -> list[SaveSettingsDescription]:
return [
*super().get_save_list(),
SaveSettingsDescription("segmentation_pipeline_save.json", self._segmentation_pipelines_dict),
Expand All @@ -142,27 +142,27 @@ def get_save_list(self) -> typing.List[SaveSettingsDescription]:
]

@property
def segmentation_pipelines(self) -> typing.Dict[str, SegmentationPipeline]:
def segmentation_pipelines(self) -> dict[str, SegmentationPipeline]:
warnings.warn("segmentation_pipelines is deprecated, use roi_pipelines", DeprecationWarning, stacklevel=2)
return self.roi_pipelines

@property
def roi_pipelines(self) -> typing.Dict[str, SegmentationPipeline]:
def roi_pipelines(self) -> dict[str, SegmentationPipeline]:
return self._segmentation_pipelines_dict.get(self._current_roi_dict, EventedDict())

@property
def segmentation_profiles(self) -> typing.Dict[str, ROIExtractionProfile]:
def segmentation_profiles(self) -> dict[str, ROIExtractionProfile]:
warnings.warn("segmentation_profiles is deprecated, use roi_profiles", DeprecationWarning, stacklevel=2)
return self.roi_profiles

@property
def roi_profiles(self) -> typing.Dict[str, ROIExtractionProfile]:
def roi_profiles(self) -> dict[str, ROIExtractionProfile]:
return self._segmentation_profiles_dict.get(self._current_roi_dict, EventedDict())

@property
def batch_plans(self) -> typing.Dict[str, CalculationPlan]:
def batch_plans(self) -> dict[str, CalculationPlan]:
return self._batch_plans_dict.get(self._current_roi_dict, EventedDict())

@property
def measurement_profiles(self) -> typing.Dict[str, MeasurementProfile]:
def measurement_profiles(self) -> dict[str, MeasurementProfile]:
return self._measurement_profiles_dict.get(self._current_roi_dict, EventedDict())
12 changes: 5 additions & 7 deletions package/PartSeg/_roi_analysis/prepare_plan_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,17 +294,15 @@ def enable_protect(self):
self.protect = previous

@classmethod
def refresh_profiles(
cls, list_widget: typing.Union[QListWidget, SearchableListWidget], new_values: typing.List[str]
):
def refresh_profiles(cls, list_widget: typing.Union[QListWidget, SearchableListWidget], new_values: list[str]):
index = cls.get_index(list_widget.currentItem(), new_values)
list_widget.clear()
list_widget.addItems(new_values)
if index != -1:
list_widget.setCurrentRow(index)

@staticmethod
def get_index(item: QListWidgetItem, new_values: typing.List[str]) -> int:
def get_index(item: QListWidgetItem, new_values: list[str]) -> int:
if item is None:
return -1
text = item.text()
Expand All @@ -319,7 +317,7 @@ class OtherOperations(ProtectedGroupBox):

def __init__(self, parent=None):
super().__init__("Other operations:", parent)
self.save_translate_dict: typing.Dict[str, SaveBase] = {x.get_short_name(): x for x in save_dict.values()}
self.save_translate_dict: dict[str, SaveBase] = {x.get_short_name(): x for x in save_dict.values()}
self.save_constructor = None

self.change_root = QEnumComboBox(self, enum_class=RootType)
Expand Down Expand Up @@ -642,7 +640,7 @@ def __init__(self, settings: PartSettings, parent: typing.Optional[QWidget] = No

self.add_mask_btn.setDisabled(True)

def update_mask_set(self, mask_set: typing.Set[str]):
def update_mask_set(self, mask_set: set[str]):
self.mask_set = mask_set

def set_replace(self, replace: bool):
Expand Down Expand Up @@ -692,7 +690,7 @@ class CreatePlan(QWidget):
def __init__(self, settings: PartSettings):
super().__init__()
self.settings = settings
self.save_translate_dict: typing.Dict[str, SaveBase] = {x.get_short_name(): x for x in save_dict.values()}
self.save_translate_dict: dict[str, SaveBase] = {x.get_short_name(): x for x in save_dict.values()}
self._mask_set = set()
self.plan = PlanPreview(self)
self.save_plan_btn = QPushButton("Save")
Expand Down
8 changes: 4 additions & 4 deletions package/PartSeg/_roi_analysis/profile_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,10 @@ def get_checked(self):
class ImportDialog(QDialog):
def __init__(
self,
import_dict: typing.Dict[str, typing.Any],
local_dict: typing.Dict[str, typing.Any],
viewer: typing.Type[ObjectPreviewProtocol],
expected_type: typing.Optional[typing.Type] = None,
import_dict: dict[str, typing.Any],
local_dict: dict[str, typing.Any],
viewer: type[ObjectPreviewProtocol],
expected_type: typing.Optional[type] = None,
parent: typing.Optional[QWidget] = None,
):
"""
Expand Down
Loading

0 comments on commit 6d348fc

Please sign in to comment.