diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml index 9b24e7f..5f9ed4b 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -20,7 +20,7 @@ jobs: fail-fast: false matrix: platform: [ubuntu-latest, macos-latest, windows-latest] - python-version: ['3.9', '3.10', '3.11'] + python-version: ['3.10', '3.11', '3.12'] steps: - uses: actions/checkout@v3 @@ -64,7 +64,7 @@ jobs: if: github.event_name != 'merge_group' with: token: ${{ secrets.CODECOV_TOKEN }} - fail_ci_if_error: true + fail_ci_if_error: false diff --git a/docs/changelog.rst b/docs/changelog.rst index 255982a..ff2e60c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,5 +1,14 @@ Changelog ========= +2.0.2 +----- +Dependencies +~~~~~~~~~~~~ +napari-matplotlib now adheres to `SPEC 0 `_, and has: +- Dropped support for Python 3.9 +- Added support for Python 3.12 +- Added a minimum required numpy verison of 1.23 + 2.0.1 ----- Bug fixes diff --git a/pyproject.toml b/pyproject.toml index ba9f9e6..bbec409 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,8 @@ filterwarnings = [ # Coming from vispy "ignore:distutils Version classes are deprecated:DeprecationWarning", "ignore:`np.bool8` is a deprecated alias for `np.bool_`:DeprecationWarning", + # Coming from pydantic via napari + "ignore:Pickle, copy, and deepcopy support will be removed from itertools in Python 3.14.:DeprecationWarning" ] qt_api = "pyqt6" addopts = "--mpl --mpl-baseline-relative" @@ -24,7 +26,7 @@ profile = "black" line_length = 79 [tool.ruff] -target-version = "py39" +target-version = "py310" select = ["I", "UP", "F", "E", "W", "D"] ignore = [ "D100", # Missing docstring in public module @@ -46,7 +48,7 @@ fix = true convention = "numpy" [tool.mypy] -python_version = "3.9" +python_version = "3.10" # Block below are checks that form part of mypy 'strict' mode strict = true disallow_subclassing_any = false # TODO: fix diff --git a/setup.cfg b/setup.cfg index 76fc8bf..2b74504 100644 --- a/setup.cfg +++ b/setup.cfg @@ -29,9 +29,9 @@ packages = find: install_requires = matplotlib napari - numpy + numpy>=1.23 tinycss2 -python_requires = >=3.9 +python_requires = >=3.10 include_package_data = True package_dir = =src diff --git a/src/napari_matplotlib/base.py b/src/napari_matplotlib/base.py index fb9e485..c455335 100644 --- a/src/napari_matplotlib/base.py +++ b/src/napari_matplotlib/base.py @@ -1,6 +1,5 @@ import os from pathlib import Path -from typing import Optional import matplotlib.style as mplstyle import napari @@ -38,7 +37,7 @@ class BaseNapariMPLWidget(QWidget): def __init__( self, napari_viewer: napari.Viewer, - parent: Optional[QWidget] = None, + parent: QWidget | None = None, ): super().__init__(parent=parent) self.viewer = napari_viewer @@ -173,7 +172,7 @@ class NapariMPLWidget(BaseNapariMPLWidget): def __init__( self, napari_viewer: napari.viewer.Viewer, - parent: Optional[QWidget] = None, + parent: QWidget | None = None, ): super().__init__(napari_viewer=napari_viewer, parent=parent) self._setup_callbacks() @@ -282,7 +281,7 @@ class SingleAxesWidget(NapariMPLWidget): def __init__( self, napari_viewer: napari.viewer.Viewer, - parent: Optional[QWidget] = None, + parent: QWidget | None = None, ): super().__init__(napari_viewer=napari_viewer, parent=parent) self.add_single_axes() diff --git a/src/napari_matplotlib/histogram.py b/src/napari_matplotlib/histogram.py index 4076528..a0b6e09 100644 --- a/src/napari_matplotlib/histogram.py +++ b/src/napari_matplotlib/histogram.py @@ -1,4 +1,4 @@ -from typing import Any, Optional, cast +from typing import Any, cast import napari import numpy as np @@ -44,7 +44,7 @@ class HistogramWidget(SingleAxesWidget): def __init__( self, napari_viewer: napari.viewer.Viewer, - parent: Optional[QWidget] = None, + parent: QWidget | None = None, ): super().__init__(napari_viewer, parent=parent) self._update_layers(None) @@ -121,7 +121,7 @@ class FeaturesHistogramWidget(SingleAxesWidget): def __init__( self, napari_viewer: napari.viewer.Viewer, - parent: Optional[QWidget] = None, + parent: QWidget | None = None, ): super().__init__(napari_viewer, parent=parent) @@ -137,12 +137,12 @@ def __init__( self._update_layers(None) @property - def x_axis_key(self) -> Optional[str]: + def x_axis_key(self) -> str | None: """Key to access x axis data from the FeaturesTable""" return self._x_axis_key @x_axis_key.setter - def x_axis_key(self, key: Optional[str]) -> None: + def x_axis_key(self, key: str | None) -> None: self._x_axis_key = key self._draw() @@ -166,7 +166,7 @@ def _get_valid_axis_keys(self) -> list[str]: else: return self.layers[0].features.keys() - def _get_data(self) -> tuple[Optional[npt.NDArray[Any]], str]: + def _get_data(self) -> tuple[npt.NDArray[Any] | None, str]: """Get the plot data. Returns diff --git a/src/napari_matplotlib/scatter.py b/src/napari_matplotlib/scatter.py index 67d6896..98ebe92 100644 --- a/src/napari_matplotlib/scatter.py +++ b/src/napari_matplotlib/scatter.py @@ -1,4 +1,4 @@ -from typing import Any, Optional, Union +from typing import Any import napari import numpy.typing as npt @@ -100,7 +100,7 @@ class FeaturesScatterWidget(ScatterBaseWidget): def __init__( self, napari_viewer: napari.viewer.Viewer, - parent: Optional[QWidget] = None, + parent: QWidget | None = None, ): super().__init__(napari_viewer, parent=parent) @@ -118,7 +118,7 @@ def __init__( self._update_layers(None) @property - def x_axis_key(self) -> Union[str, None]: + def x_axis_key(self) -> str | None: """ Key for the x-axis data. """ @@ -133,7 +133,7 @@ def x_axis_key(self, key: str) -> None: self._draw() @property - def y_axis_key(self) -> Union[str, None]: + def y_axis_key(self) -> str | None: """ Key for the y-axis data. """ diff --git a/src/napari_matplotlib/slice.py b/src/napari_matplotlib/slice.py index 9459fa9..1924bf2 100644 --- a/src/napari_matplotlib/slice.py +++ b/src/napari_matplotlib/slice.py @@ -1,4 +1,4 @@ -from typing import Any, Optional +from typing import Any import matplotlib.ticker as mticker import napari @@ -30,7 +30,7 @@ class SliceWidget(SingleAxesWidget): def __init__( self, napari_viewer: napari.viewer.Viewer, - parent: Optional[QWidget] = None, + parent: QWidget | None = None, ): # Setup figure/axes super().__init__(napari_viewer, parent=parent) diff --git a/src/napari_matplotlib/util.py b/src/napari_matplotlib/util.py index ed99425..c54b60a 100644 --- a/src/napari_matplotlib/util.py +++ b/src/napari_matplotlib/util.py @@ -1,4 +1,3 @@ -from typing import Optional, Union from warnings import warn import napari.qt @@ -12,7 +11,7 @@ class Interval: An integer interval. """ - def __init__(self, lower_bound: Optional[int], upper_bound: Optional[int]): + def __init__(self, lower_bound: int | None, upper_bound: int | None): """ Parameters ---------- @@ -48,7 +47,7 @@ def __contains__(self, val: int) -> bool: return True @property - def _helper_text(self) -> Optional[str]: + def _helper_text(self) -> str | None: """ Helper text for widgets. """ @@ -86,9 +85,7 @@ def _has_id(nodes: list[tinycss2.ast.Node], id_name: str) -> bool: ) -def _get_dimension( - nodes: list[tinycss2.ast.Node], id_name: str -) -> Union[int, None]: +def _get_dimension(nodes: list[tinycss2.ast.Node], id_name: str) -> int | None: """ Get the value of the DimensionToken for the IdentToken `id_name`. diff --git a/tox.ini b/tox.ini index 4ec0c70..f4aed6a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,12 +1,12 @@ [tox] -envlist = py{39,310,311} +envlist = py{310,311,312} isolated_build = true [gh-actions] python = - 3.9: py39 3.10: py310 3.11: py311 + 3.12: py312 [testenv] extras = testing