Browse Source

drop compatibility with python3.6

checklist:
- changelog
- setup.py
- .github/workflows/python.yml
- typing.NoReturn
- from __future__ import annotations
- dataclasses
- collections.namedtuple default values
- datetime.datetime.fromisoformat

https://github.com/fphammerle/ical2vdir/commit/2b32144312b59398a91d4814ea1d3981076b3238
https://github.com/fphammerle/acpi-backlight/commit/6bcb9e76e45fc9564ad78feb8d211e6ac950bc65
Fabian Peter Hammerle 2 years ago
parent
commit
2bc6d35e82
5 changed files with 35 additions and 19 deletions
  1. 0 2
      .github/workflows/python.yml
  2. 5 1
      CHANGELOG.md
  3. 14 14
      freesurfer_surface/__init__.py
  4. 2 2
      setup.py
  5. 14 0
      tests/test_label.py

+ 0 - 2
.github/workflows/python.yml

@@ -34,7 +34,6 @@ jobs:
     strategy:
       matrix:
         python-version:
-        - '3.6'
         - '3.7'
         - '3.8'
         - '3.9'
@@ -69,7 +68,6 @@ jobs:
     strategy:
       matrix:
         python-version:
-        - '3.6'
         - '3.7'
         - '3.8'
         - '3.9'

+ 5 - 1
CHANGELOG.md

@@ -6,8 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 ### Added
+- equals operator for `Label` class
 - package metadata: added link to changelog
 
+### Removed
+- compatibility with `python3.6`
+
 ## [2.0.0] - 2021-05-22
 ### Removed
 - compatibility with `python3.5`
@@ -79,7 +83,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - `Surface.add_rectangle`: accept 3 or 4 vertex indices (previously only 3)
 
 ### Changed
-- dervice `Vertex` from `numpy.ndarray` (previously `collections.namedtuple`)
+- derive `Vertex` from `numpy.ndarray` (previously `collections.namedtuple`)
 
 ### Fixed
 * `Surface._find_label_border_segments`: failing on incompletely labelled set of vertices

+ 14 - 14
freesurfer_surface/__init__.py

@@ -53,9 +53,12 @@ Find Border of Labelled Region
 >>> print(surface.find_label_border_polygonal_chains(region))
 """
 
+from __future__ import annotations
+
 import collections
 import contextlib
 import copy
+import dataclasses
 import datetime
 import itertools
 import locale
@@ -124,7 +127,7 @@ class Vertex(numpy.ndarray):
         return f"{type(self).__name__}({self.__format_coords()})"
 
     def distance_mm(
-        self, others: typing.Union["Vertex", typing.Iterable["Vertex"], numpy.ndarray]
+        self, others: typing.Union[Vertex, typing.Iterable[Vertex], numpy.ndarray]
     ) -> numpy.ndarray:
         if isinstance(others, Vertex):
             others = others.reshape((1, 3))
@@ -140,7 +143,7 @@ class PolygonalCircuit:
     def vertex_indices(self):
         return self._vertex_indices
 
-    def _normalize(self) -> "PolygonalCircuit":
+    def _normalize(self) -> PolygonalCircuit:
         vertex_indices = collections.deque(self.vertex_indices)
         vertex_indices.rotate(-numpy.argmin(self.vertex_indices))
         if len(vertex_indices) > 2 and vertex_indices[-1] < vertex_indices[1]:
@@ -205,7 +208,7 @@ class PolygonalChain:
     def __init__(self, vertex_indices: typing.Iterable[int]):
         self.vertex_indices: typing.Deque[int] = collections.deque(vertex_indices)
 
-    def normalized(self) -> "PolygonalChain":
+    def normalized(self) -> PolygonalChain:
         vertex_indices = list(self.vertex_indices)
         min_index = vertex_indices.index(min(vertex_indices))
         indices_min_first = vertex_indices[min_index:] + vertex_indices[:min_index]
@@ -222,7 +225,7 @@ class PolygonalChain:
     def __repr__(self) -> str:
         return f"PolygonalChain(vertex_indices={tuple(self.vertex_indices)})"
 
-    def connect(self, other: "PolygonalChain") -> None:
+    def connect(self, other: PolygonalChain) -> None:
         if self.vertex_indices[-1] == other.vertex_indices[0]:
             self.vertex_indices.pop()
             self.vertex_indices.extend(other.vertex_indices)
@@ -252,18 +255,15 @@ class PolygonalChain:
         return map(LineSegment, self.adjacent_vertex_indices(2))
 
 
+@dataclasses.dataclass
 class Label:
 
-    # pylint: disable=too-many-arguments
-    def __init__(
-        self, index: int, name: str, red: int, green: int, blue: int, transparency: int
-    ):
-        self.index: int = index
-        self.name: str = name
-        self.red: int = red
-        self.green: int = green
-        self.blue: int = blue
-        self.transparency: int = transparency
+    index: int
+    name: str
+    red: int
+    green: int
+    blue: int
+    transparency: int
 
     @property
     def color_code(self) -> int:

+ 2 - 2
setup.py

@@ -56,7 +56,6 @@ setuptools.setup(
         "Intended Audience :: Healthcare Industry",
         "Intended Audience :: Science/Research",
         # .github/workflows/python.yml
-        "Programming Language :: Python :: 3.6",
         "Programming Language :: Python :: 3.7",
         "Programming Language :: Python :: 3.8",
         "Programming Language :: Python :: 3.9",
@@ -71,7 +70,8 @@ setuptools.setup(
             "unite-freesurfer-surfaces = freesurfer_surface.__main__:unite_surfaces",
         ]
     },
-    python_requires=">=3.6",
+    # >=3.7 for postponed evaluation of type annotations (PEP563) & dataclass
+    python_requires=">=3.7",
     install_requires=["numpy<2"],
     setup_requires=["setuptools_scm"],
     tests_require=["pytest<5"],

+ 14 - 0
tests/test_label.py

@@ -20,6 +20,20 @@ import pytest
 from freesurfer_surface import Label
 
 
+def test_init_missing_argument():
+    with pytest.raises(
+        TypeError, match=r"missing 1 required positional argument: .transparency.$"
+    ):
+        # pylint: disable=no-value-for-parameter
+        Label(index=0, name="test", red=1, green=2, blue=3)
+
+
+def test_eq():
+    kwargs = dict(name="test", red=1, green=2, blue=3, transparency=0)
+    assert Label(index=21, **kwargs) == Label(index=21, **kwargs)
+    assert Label(index=21, **kwargs) != Label(index=42, **kwargs)
+
+
 @pytest.mark.parametrize(
     ("red", "green", "blue", "transparency", "color_code"),
     [