Browse Source

black format

Fabian Peter Hammerle 7 months ago
parent
commit
8bffd9327a

+ 1 - 0
.travis.yml

@@ -16,6 +16,7 @@ install:
 script:
 - pipenv run pylint freesurfer_surface tests/*
 - pipenv run pytest --cov=freesurfer_surface --cov-report=term-missing --cov-fail-under=100
+- pipenv run black --check .
 
 after_success:
 - pip install coveralls

+ 1 - 0
Pipfile

@@ -7,6 +7,7 @@ name = "pypi"
 freesurfer-surface = {editable = true, path = "."}
 
 [dev-packages]
+black = "==19.10b0"
 pylint = ">=2.3.0,<3"
 pytest = "<5"
 pytest-cov = "<3,>=2"

+ 63 - 1
Pipfile.lock

@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "803d32a037feb7833276e483dc360026bd99e45f1fafaf9dc5ccde67f1469424"
+            "sha256": "d7e371875adda413bb4761bf12f360a8d3e53cf478866466da496551380c702c"
         },
         "pipfile-spec": 6,
         "requires": {
@@ -48,6 +48,13 @@
         }
     },
     "develop": {
+        "appdirs": {
+            "hashes": [
+                "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92",
+                "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"
+            ],
+            "version": "==1.4.3"
+        },
         "astroid": {
             "hashes": [
                 "sha256:71ea07f44df9568a75d0f354c49143a4575d90645e9fead6dfb52c26a85ed13a",
@@ -76,6 +83,21 @@
             "index": "pypi",
             "version": "==1.5"
         },
+        "black": {
+            "hashes": [
+                "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b",
+                "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"
+            ],
+            "index": "pypi",
+            "version": "==19.10b0"
+        },
+        "click": {
+            "hashes": [
+                "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
+                "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
+            ],
+            "version": "==7.0"
+        },
         "coverage": {
             "hashes": [
                 "sha256:15cf13a6896048d6d947bf7d222f36e4809ab926894beb748fc9caa14605d9c3",
@@ -176,6 +198,13 @@
             ],
             "version": "==20.1"
         },
+        "pathspec": {
+            "hashes": [
+                "sha256:163b0632d4e31cef212976cf57b43d9fd6b0bac6e67c26015d611a647d5e7424",
+                "sha256:562aa70af2e0d434367d9790ad37aed893de47f1693e4201fd1d3dca15d19b96"
+            ],
+            "version": "==0.7.0"
+        },
         "pluggy": {
             "hashes": [
                 "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
@@ -228,6 +257,32 @@
             "index": "pypi",
             "version": "==2.8.1"
         },
+        "regex": {
+            "hashes": [
+                "sha256:07b39bf943d3d2fe63d46281d8504f8df0ff3fe4c57e13d1656737950e53e525",
+                "sha256:0932941cdfb3afcbc26cc3bcf7c3f3d73d5a9b9c56955d432dbf8bbc147d4c5b",
+                "sha256:0e182d2f097ea8549a249040922fa2b92ae28be4be4895933e369a525ba36576",
+                "sha256:10671601ee06cf4dc1bc0b4805309040bb34c9af423c12c379c83d7895622bb5",
+                "sha256:23e2c2c0ff50f44877f64780b815b8fd2e003cda9ce817a7fd00dea5600c84a0",
+                "sha256:26ff99c980f53b3191d8931b199b29d6787c059f2e029b2b0c694343b1708c35",
+                "sha256:27429b8d74ba683484a06b260b7bb00f312e7c757792628ea251afdbf1434003",
+                "sha256:3e77409b678b21a056415da3a56abfd7c3ad03da71f3051bbcdb68cf44d3c34d",
+                "sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161",
+                "sha256:4eae742636aec40cf7ab98171ab9400393360b97e8f9da67b1867a9ee0889b26",
+                "sha256:6a6ae17bf8f2d82d1e8858a47757ce389b880083c4ff2498dba17c56e6c103b9",
+                "sha256:6a6ba91b94427cd49cd27764679024b14a96874e0dc638ae6bdd4b1a3ce97be1",
+                "sha256:7bcd322935377abcc79bfe5b63c44abd0b29387f267791d566bbb566edfdd146",
+                "sha256:98b8ed7bb2155e2cbb8b76f627b2fd12cf4b22ab6e14873e8641f266e0fb6d8f",
+                "sha256:bd25bb7980917e4e70ccccd7e3b5740614f1c408a642c245019cff9d7d1b6149",
+                "sha256:d0f424328f9822b0323b3b6f2e4b9c90960b24743d220763c7f07071e0778351",
+                "sha256:d58e4606da2a41659c84baeb3cfa2e4c87a74cec89a1e7c56bee4b956f9d7461",
+                "sha256:e3cd21cc2840ca67de0bbe4071f79f031c81418deb544ceda93ad75ca1ee9f7b",
+                "sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242",
+                "sha256:e7c7661f7276507bce416eaae22040fd91ca471b5b33c13f8ff21137ed6f248c",
+                "sha256:ecc6de77df3ef68fee966bb8cb4e067e84d4d1f397d0ef6fce46913663540d77"
+            ],
+            "version": "==2020.1.8"
+        },
         "six": {
             "hashes": [
                 "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
@@ -235,6 +290,13 @@
             ],
             "version": "==1.14.0"
         },
+        "toml": {
+            "hashes": [
+                "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c",
+                "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"
+            ],
+            "version": "==0.10.0"
+        },
         "typed-ast": {
             "hashes": [
                 "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355",

+ 2 - 0
README.rst

@@ -1,6 +1,8 @@
 freesurfer-surface
 ==================
 
+.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
+   :target: https://github.com/psf/black
 .. image:: https://travis-ci.org/fphammerle/freesurfer-surface.svg?branch=master
    :target: https://travis-ci.org/fphammerle/freesurfer-surface
 .. image:: https://coveralls.io/repos/github/fphammerle/freesurfer-surface/badge.svg?branch=master

+ 229 - 157
freesurfer_surface/__init__.py

@@ -61,7 +61,7 @@ def setlocale(temporary_locale):
     try:
         yield locale.setlocale(locale.LC_ALL, temporary_locale)
     except locale.Error as exc:
-        if str(exc) == 'unsupported locale setting':
+        if str(exc) == "unsupported locale setting":
             raise UnsupportedLocaleSettingError(temporary_locale)
         raise exc  # pragma: no cover
     finally:
@@ -69,10 +69,8 @@ def setlocale(temporary_locale):
 
 
 class Vertex(numpy.ndarray):
-
     def __new__(cls, right: float, anterior: float, superior: float):
-        return numpy.array((right, anterior, superior),
-                           dtype=float).view(cls)
+        return numpy.array((right, anterior, superior), dtype=float).view(cls)
 
     @property
     def right(self) -> float:
@@ -88,21 +86,24 @@ class Vertex(numpy.ndarray):
 
     @property
     def __dict__(self) -> typing.Dict[str, float]:
-        return {'right': self.right,
-                'anterior': self.anterior,
-                'superior': self.superior}
+        return {
+            "right": self.right,
+            "anterior": self.anterior,
+            "superior": self.superior,
+        }
 
     def __format_coords(self) -> str:
-        return ', '.join('{}={}'.format(name, getattr(self, name))
-                         for name in ['right', 'anterior', 'superior'])
+        return ", ".join(
+            "{}={}".format(name, getattr(self, name))
+            for name in ["right", "anterior", "superior"]
+        )
 
     def __repr__(self) -> str:
-        return '{}({})'.format(type(self).__name__, self.__format_coords())
+        return "{}({})".format(type(self).__name__, self.__format_coords())
 
-    def distance_mm(self, others: typing.Union['Vertex',
-                                               typing.Iterable['Vertex'],
-                                               numpy.ndarray],
-                    ) -> numpy.ndarray:
+    def distance_mm(
+        self, others: typing.Union["Vertex", typing.Iterable["Vertex"], numpy.ndarray],
+    ) -> numpy.ndarray:
         if isinstance(others, Vertex):
             others = others.reshape((1, 3))
         return numpy.linalg.norm(self - others, axis=1)
@@ -120,7 +121,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]:
@@ -128,7 +129,7 @@ class PolygonalCircuit:
             vertex_indices.rotate(1)
         return type(self)(vertex_indices)
 
-    def __eq__(self, other: 'PolygonalCircuit') -> bool:
+    def __eq__(self, other: "PolygonalCircuit") -> bool:
         # pylint: disable=protected-access
         return self._normalize().vertex_indices == other._normalize().vertex_indices
 
@@ -136,37 +137,42 @@ class PolygonalCircuit:
         # pylint: disable=protected-access
         return hash(self._normalize()._vertex_indices)
 
-    def adjacent_vertex_indices(self, vertices_num: int = 2
-                                ) -> typing.Iterable[typing.Tuple[int]]:
-        vertex_indices_cycle = list(itertools.islice(
-            itertools.cycle(self.vertex_indices),
-            0,
-            len(self.vertex_indices) + vertices_num - 1,
-        ))
-        return zip(*(itertools.islice(vertex_indices_cycle,
-                                      offset,
-                                      len(self.vertex_indices) + offset)
-                     for offset in range(vertices_num)))
+    def adjacent_vertex_indices(
+        self, vertices_num: int = 2
+    ) -> typing.Iterable[typing.Tuple[int]]:
+        vertex_indices_cycle = list(
+            itertools.islice(
+                itertools.cycle(self.vertex_indices),
+                0,
+                len(self.vertex_indices) + vertices_num - 1,
+            )
+        )
+        return zip(
+            *(
+                itertools.islice(
+                    vertex_indices_cycle, offset, len(self.vertex_indices) + offset
+                )
+                for offset in range(vertices_num)
+            )
+        )
 
 
 class LineSegment(PolygonalCircuit):
-
     def __init__(self, indices: PolygonalCircuit._VERTEX_INDICES_TYPE):
         super().__init__(indices)
         assert len(self.vertex_indices) == 2
 
     def __repr__(self) -> str:
-        return 'LineSegment(vertex_indices={})'.format(self.vertex_indices)
+        return "LineSegment(vertex_indices={})".format(self.vertex_indices)
 
 
 class Triangle(PolygonalCircuit):
-
     def __init__(self, indices: PolygonalCircuit._VERTEX_INDICES_TYPE):
         super().__init__(indices)
         assert len(self.vertex_indices) == 3
 
     def __repr__(self) -> str:
-        return 'Triangle(vertex_indices={})'.format(self.vertex_indices)
+        return "Triangle(vertex_indices={})".format(self.vertex_indices)
 
 
 class PolygonalChainsNotOverlapingError(ValueError):
@@ -174,18 +180,16 @@ class PolygonalChainsNotOverlapingError(ValueError):
 
 
 class PolygonalChain:
-
     def __init__(self, vertex_indices: typing.Iterable[int]):
-        self.vertex_indices \
-            = collections.deque(vertex_indices)  # type: Deque[int]
+        self.vertex_indices = collections.deque(vertex_indices)  # type: Deque[int]
 
-    def __eq__(self, other: 'PolygonalChain') -> bool:
+    def __eq__(self, other: "PolygonalChain") -> bool:
         return self.vertex_indices == other.vertex_indices
 
     def __repr__(self) -> str:
-        return 'PolygonalChain(vertex_indices={})'.format(tuple(self.vertex_indices))
+        return "PolygonalChain(vertex_indices={})".format(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)
@@ -201,12 +205,15 @@ class PolygonalChain:
         else:
             raise PolygonalChainsNotOverlapingError()
 
-    def adjacent_vertex_indices(self, vertices_num: int = 2
-                                ) -> typing.Iterable[typing.Tuple[int]]:
-        return zip(*(itertools.islice(self.vertex_indices,
-                                      offset,
-                                      len(self.vertex_indices))
-                     for offset in range(vertices_num)))
+    def adjacent_vertex_indices(
+        self, vertices_num: int = 2
+    ) -> typing.Iterable[typing.Tuple[int]]:
+        return zip(
+            *(
+                itertools.islice(self.vertex_indices, offset, len(self.vertex_indices))
+                for offset in range(vertices_num)
+            )
+        )
 
     def segments(self) -> typing.Iterable[LineSegment]:
         return map(LineSegment, self.adjacent_vertex_indices(2))
@@ -215,8 +222,9 @@ class PolygonalChain:
 class Label:
 
     # pylint: disable=too-many-arguments
-    def __init__(self, index: int, name: str, red: int,
-                 green: int, blue: int, transparency: int):
+    def __init__(
+        self, index: int, name: str, red: int, green: int, blue: int, transparency: int
+    ):
         self.index = index  # type: int
         self.name = name  # type: str
         self.red = red  # type: int
@@ -228,16 +236,20 @@ class Label:
     def color_code(self) -> int:
         if self.index == 0:  # unknown
             return 0
-        return int.from_bytes((self.red, self.green, self.blue, self.transparency),
-                              byteorder='little', signed=False)
+        return int.from_bytes(
+            (self.red, self.green, self.blue, self.transparency),
+            byteorder="little",
+            signed=False,
+        )
 
     @property
     def hex_color_code(self) -> str:
-        return '#{:02x}{:02x}{:02x}'.format(self.red, self.green, self.blue)
+        return "#{:02x}{:02x}{:02x}".format(self.red, self.green, self.blue)
 
     def __str__(self) -> str:
-        return 'Label(name={}, index={}, color={})'.format(
-            self.name, self.index, self.hex_color_code)
+        return "Label(name={}, index={}, color={})".format(
+            self.name, self.index, self.hex_color_code
+        )
 
     def __repr__(self) -> str:
         return str(self)
@@ -247,7 +259,7 @@ class Annotation:
 
     # pylint: disable=too-few-public-methods
 
-    _TAG_OLD_COLORTABLE = b'\0\0\0\x01'
+    _TAG_OLD_COLORTABLE = b"\0\0\0\x01"
 
     def __init__(self):
         self.vertex_label_index = {}  # type: Dict[int, int]
@@ -256,38 +268,50 @@ class Annotation:
 
     @staticmethod
     def _read_label(stream: typing.BinaryIO) -> Label:
-        index, name_length = struct.unpack('>II', stream.read(4 * 2))
+        index, name_length = struct.unpack(">II", stream.read(4 * 2))
         name = stream.read(name_length - 1).decode()
-        assert stream.read(1) == b'\0'
-        red, green, blue, transparency \
-            = struct.unpack('>IIII', stream.read(4 * 4))
-        return Label(index=index, name=name, red=red, green=green,
-                     blue=blue, transparency=transparency)
+        assert stream.read(1) == b"\0"
+        red, green, blue, transparency = struct.unpack(">IIII", stream.read(4 * 4))
+        return Label(
+            index=index,
+            name=name,
+            red=red,
+            green=green,
+            blue=blue,
+            transparency=transparency,
+        )
 
     def _read(self, stream: typing.BinaryIO) -> None:
         # https://surfer.nmr.mgh.harvard.edu/fswiki/LabelsClutsAnnotationFiles
-        annotations_num, = struct.unpack('>I', stream.read(4))
-        annotations = [struct.unpack('>II', stream.read(4 * 2))
-                       for _ in range(annotations_num)]
+        (annotations_num,) = struct.unpack(">I", stream.read(4))
+        annotations = [
+            struct.unpack(">II", stream.read(4 * 2)) for _ in range(annotations_num)
+        ]
         assert stream.read(4) == self._TAG_OLD_COLORTABLE
-        colortable_version, _, filename_length \
-            = struct.unpack('>III', stream.read(4 * 3))
+        colortable_version, _, filename_length = struct.unpack(
+            ">III", stream.read(4 * 3)
+        )
         assert colortable_version > 0  # new version
         self.colortable_path = stream.read(filename_length - 1)
-        assert stream.read(1) == b'\0'
-        labels_num, = struct.unpack('>I', stream.read(4))
-        self.labels = {label.index: label for label
-                       in (self._read_label(stream) for _ in range(labels_num))}
-        label_index_by_color_code = {label.color_code: label.index
-                                     for label in self.labels.values()}
-        self.vertex_label_index = {vertex_index: label_index_by_color_code[color_code]
-                                   for vertex_index, color_code in annotations}
+        assert stream.read(1) == b"\0"
+        (labels_num,) = struct.unpack(">I", stream.read(4))
+        self.labels = {
+            label.index: label
+            for label in (self._read_label(stream) for _ in range(labels_num))
+        }
+        label_index_by_color_code = {
+            label.color_code: label.index for label in self.labels.values()
+        }
+        self.vertex_label_index = {
+            vertex_index: label_index_by_color_code[color_code]
+            for vertex_index, color_code in annotations
+        }
         assert not stream.read(1)
 
     @classmethod
-    def read(cls, annotation_file_path: str) -> 'Annotation':
+    def read(cls, annotation_file_path: str) -> "Annotation":
         annotation = cls()
-        with open(annotation_file_path, 'rb') as annotation_file:
+        with open(annotation_file_path, "rb") as annotation_file:
             # pylint: disable=protected-access
             annotation._read(annotation_file)
         return annotation
@@ -297,13 +321,13 @@ class Surface:
 
     # pylint: disable=too-many-instance-attributes
 
-    _MAGIC_NUMBER = b'\xff\xff\xfe'
+    _MAGIC_NUMBER = b"\xff\xff\xfe"
 
-    _TAG_CMDLINE = b'\x00\x00\x00\x03'
-    _TAG_OLD_SURF_GEOM = b'\x00\x00\x00\x14'
-    _TAG_OLD_USEREALRAS = b'\x00\x00\x00\x02'
+    _TAG_CMDLINE = b"\x00\x00\x00\x03"
+    _TAG_OLD_SURF_GEOM = b"\x00\x00\x00\x14"
+    _TAG_OLD_USEREALRAS = b"\x00\x00\x00\x02"
 
-    _DATETIME_FORMAT = '%a %b %d %H:%M:%S %Y'
+    _DATETIME_FORMAT = "%a %b %d %H:%M:%S %Y"
 
     def __init__(self):
         self.creator = None  # type: Optional[bytes]
@@ -324,30 +348,38 @@ class Surface:
             assert tag == cls._TAG_CMDLINE  # might be TAG_GROUP_AVG_SURFACE_AREA
             # TAGwrite
             # https://github.com/freesurfer/freesurfer/blob/release_6_0_0/utils/tags.c#L94
-            str_length, = struct.unpack('>Q', stream.read(8))
+            (str_length,) = struct.unpack(">Q", stream.read(8))
             yield stream.read(str_length - 1)
-            assert stream.read(1) == b'\x00'
+            assert stream.read(1) == b"\x00"
 
     def _read_triangular(self, stream: typing.BinaryIO):
         assert stream.read(3) == self._MAGIC_NUMBER
-        self.creator, creation_dt_str = re.match(rb'^created by (\w+) on (.* \d{4})\n',
-                                                 stream.readline()).groups()
-        with setlocale('C'):
-            self.creation_datetime = datetime.datetime.strptime(creation_dt_str.decode(),
-                                                                self._DATETIME_FORMAT)
-        assert stream.read(1) == b'\n'
+        self.creator, creation_dt_str = re.match(
+            rb"^created by (\w+) on (.* \d{4})\n", stream.readline()
+        ).groups()
+        with setlocale("C"):
+            self.creation_datetime = datetime.datetime.strptime(
+                creation_dt_str.decode(), self._DATETIME_FORMAT
+            )
+        assert stream.read(1) == b"\n"
         # fwriteInt
         # https://github.com/freesurfer/freesurfer/blob/release_6_0_0/utils/fio.c#L290
-        vertices_num, triangles_num = struct.unpack('>II', stream.read(4 * 2))
-        self.vertices = [Vertex(*struct.unpack('>fff', stream.read(4 * 3)))
-                         for _ in range(vertices_num)]
-        self.triangles = [Triangle(struct.unpack('>III', stream.read(4 * 3)))
-                          for _ in range(triangles_num)]
-        assert all(vertex_idx < vertices_num
-                   for triangle in self.triangles
-                   for vertex_idx in triangle.vertex_indices)
+        vertices_num, triangles_num = struct.unpack(">II", stream.read(4 * 2))
+        self.vertices = [
+            Vertex(*struct.unpack(">fff", stream.read(4 * 3)))
+            for _ in range(vertices_num)
+        ]
+        self.triangles = [
+            Triangle(struct.unpack(">III", stream.read(4 * 3)))
+            for _ in range(triangles_num)
+        ]
+        assert all(
+            vertex_idx < vertices_num
+            for triangle in self.triangles
+            for vertex_idx in triangle.vertex_indices
+        )
         assert stream.read(4) == self._TAG_OLD_USEREALRAS
-        using_old_real_ras, = struct.unpack('>I', stream.read(4))
+        (using_old_real_ras,) = struct.unpack(">I", stream.read(4))
         assert using_old_real_ras in [0, 1], using_old_real_ras
         self.using_old_real_ras = bool(using_old_real_ras)
         assert stream.read(4) == self._TAG_OLD_SURF_GEOM
@@ -357,46 +389,59 @@ class Surface:
         self.command_lines = list(self._read_cmdlines(stream))
 
     @classmethod
-    def read_triangular(cls, surface_file_path: str) -> 'Surface':
+    def read_triangular(cls, surface_file_path: str) -> "Surface":
         surface = cls()
-        with open(surface_file_path, 'rb') as surface_file:
+        with open(surface_file_path, "rb") as surface_file:
             # pylint: disable=protected-access
             surface._read_triangular(surface_file)
         return surface
 
     @classmethod
     def _triangular_strftime(cls, creation_datetime: datetime.datetime) -> bytes:
-        padded_day = '{:>2}'.format(creation_datetime.day)
-        fmt = cls._DATETIME_FORMAT.replace('%d', padded_day)
-        with setlocale('C'):
+        padded_day = "{:>2}".format(creation_datetime.day)
+        fmt = cls._DATETIME_FORMAT.replace("%d", padded_day)
+        with setlocale("C"):
             return creation_datetime.strftime(fmt).encode()
 
-    def write_triangular(self, surface_file_path: str,
-                         creation_datetime: typing.Optional[datetime.datetime] = None):
+    def write_triangular(
+        self,
+        surface_file_path: str,
+        creation_datetime: typing.Optional[datetime.datetime] = None,
+    ):
         if creation_datetime is None:
             creation_datetime = datetime.datetime.now()
-        with open(surface_file_path, 'wb') as surface_file:
+        with open(surface_file_path, "wb") as surface_file:
             surface_file.write(
                 self._MAGIC_NUMBER
-                + b'created by ' + self.creator
-                + b' on ' + self._triangular_strftime(creation_datetime)
-                + b'\n\n'
-                + struct.pack('>II', len(self.vertices), len(self.triangles))
+                + b"created by "
+                + self.creator
+                + b" on "
+                + self._triangular_strftime(creation_datetime)
+                + b"\n\n"
+                + struct.pack(">II", len(self.vertices), len(self.triangles))
             )
             for vertex in self.vertices:
-                surface_file.write(struct.pack('>fff', *vertex))
+                surface_file.write(struct.pack(">fff", *vertex))
             for triangle in self.triangles:
-                assert all(vertex_index < len(self.vertices)
-                           for vertex_index in triangle.vertex_indices)
-                surface_file.write(struct.pack('>III',
-                                               *triangle.vertex_indices))
-            surface_file.write(self._TAG_OLD_USEREALRAS
-                               + struct.pack('>I', 1 if self.using_old_real_ras else 0))
-            surface_file.write(self._TAG_OLD_SURF_GEOM
-                               + b''.join(self.volume_geometry_info))
+                assert all(
+                    vertex_index < len(self.vertices)
+                    for vertex_index in triangle.vertex_indices
+                )
+                surface_file.write(struct.pack(">III", *triangle.vertex_indices))
+            surface_file.write(
+                self._TAG_OLD_USEREALRAS
+                + struct.pack(">I", 1 if self.using_old_real_ras else 0)
+            )
+            surface_file.write(
+                self._TAG_OLD_SURF_GEOM + b"".join(self.volume_geometry_info)
+            )
             for command_line in self.command_lines:
-                surface_file.write(self._TAG_CMDLINE + struct.pack('>Q', len(command_line) + 1)
-                                   + command_line + b'\0')
+                surface_file.write(
+                    self._TAG_CMDLINE
+                    + struct.pack(">Q", len(command_line) + 1)
+                    + command_line
+                    + b"\0"
+                )
 
     def load_annotation_file(self, annotation_file_path: str) -> None:
         annotation = Annotation.read(annotation_file_path)
@@ -408,23 +453,29 @@ class Surface:
         self.vertices.append(vertex)
         return len(self.vertices) - 1
 
-    def add_rectangle(self, vertex_indices: typing.Iterable[int]) -> typing.Iterable[int]:
+    def add_rectangle(
+        self, vertex_indices: typing.Iterable[int]
+    ) -> typing.Iterable[int]:
         vertex_indices = list(vertex_indices)
         if len(vertex_indices) == 3:
-            vertex_indices.append(self.add_vertex(
-                self.vertices[vertex_indices[0]]
-                + self.vertices[vertex_indices[2]]
-                - self.vertices[vertex_indices[1]]
-            ))
+            vertex_indices.append(
+                self.add_vertex(
+                    self.vertices[vertex_indices[0]]
+                    + self.vertices[vertex_indices[2]]
+                    - self.vertices[vertex_indices[1]]
+                )
+            )
         assert len(vertex_indices) == 4
         self.triangles.append(Triangle(vertex_indices[:3]))
-        self.triangles.append(Triangle(vertex_indices[2:]
-                                       + vertex_indices[:1]))
-
-    def _triangle_count_by_adjacent_vertex_indices(self) \
-            -> typing.Dict[int, typing.Dict[int, int]]:
-        counts = {vertex_index: collections.defaultdict(lambda: 0)
-                  for vertex_index in range(len(self.vertices))}
+        self.triangles.append(Triangle(vertex_indices[2:] + vertex_indices[:1]))
+
+    def _triangle_count_by_adjacent_vertex_indices(
+        self,
+    ) -> typing.Dict[int, typing.Dict[int, int]]:
+        counts = {
+            vertex_index: collections.defaultdict(lambda: 0)
+            for vertex_index in range(len(self.vertices))
+        }
         for triangle in self.triangles:
             for vertex_index_pair in triangle.adjacent_vertex_indices(2):
                 counts[vertex_index_pair[0]][vertex_index_pair[1]] += 1
@@ -433,17 +484,20 @@ class Surface:
 
     def find_borders(self) -> typing.Iterator[PolygonalCircuit]:
         border_neighbours = {}
-        for vertex_index, neighbour_counts \
-                in self._triangle_count_by_adjacent_vertex_indices().items():
+        for (
+            vertex_index,
+            neighbour_counts,
+        ) in self._triangle_count_by_adjacent_vertex_indices().items():
             if not neighbour_counts:
                 yield PolygonalCircuit((vertex_index,))
             else:
-                neighbours = [neighbour_index for neighbour_index, counts
-                              in neighbour_counts.items()
-                              if counts != 2]
+                neighbours = [
+                    neighbour_index
+                    for neighbour_index, counts in neighbour_counts.items()
+                    if counts != 2
+                ]
                 if neighbours:
-                    assert len(neighbours) % 2 == 0, \
-                        (vertex_index, neighbour_counts)
+                    assert len(neighbours) % 2 == 0, (vertex_index, neighbour_counts)
                     border_neighbours[vertex_index] = neighbours
         while border_neighbours:
             vertex_index, neighbour_indices = border_neighbours.popitem()
@@ -457,11 +511,17 @@ class Surface:
                 if len(neighbour_indices) > 1:
                     border_neighbours[vertex_index] = neighbour_indices[1:]
                 vertex_index = neighbour_indices[0]
-            assert vertex_index in border_neighbours, \
-                (vertex_index, cycle_indices, border_neighbours)
+            assert vertex_index in border_neighbours, (
+                vertex_index,
+                cycle_indices,
+                border_neighbours,
+            )
             final_neighbour_indices = border_neighbours.pop(vertex_index)
-            assert final_neighbour_indices == [cycle_indices[-1]], \
-                (vertex_index, final_neighbour_indices, cycle_indices)
+            assert final_neighbour_indices == [cycle_indices[-1]], (
+                vertex_index,
+                final_neighbour_indices,
+                cycle_indices,
+            )
             yield PolygonalCircuit(cycle_indices)
 
     def _get_vertex_label_index(self, vertex_index: int) -> typing.Optional[int]:
@@ -469,17 +529,22 @@ class Surface:
 
     def _find_label_border_segments(self, label: Label) -> typing.Iterator[LineSegment]:
         for triangle in self.triangles:
-            border_vertex_indices = tuple(filter(
-                lambda i: self._get_vertex_label_index(i) == label.index,
-                triangle.vertex_indices,
-            ))
+            border_vertex_indices = tuple(
+                filter(
+                    lambda i: self._get_vertex_label_index(i) == label.index,
+                    triangle.vertex_indices,
+                )
+            )
             if len(border_vertex_indices) == 2:
                 yield LineSegment(border_vertex_indices)
 
-    def find_label_border_polygonal_chains(self, label: Label) -> typing.Iterator[PolygonalChain]:
+    def find_label_border_polygonal_chains(
+        self, label: Label
+    ) -> typing.Iterator[PolygonalChain]:
         segments = set(self._find_label_border_segments(label))
-        available_chains = collections.deque(PolygonalChain(segment.vertex_indices)
-                                             for segment in segments)
+        available_chains = collections.deque(
+            PolygonalChain(segment.vertex_indices) for segment in segments
+        )
         # irrespective of its poor performance,
         # we keep this approach since it's easy to read and fast enough
         while available_chains:
@@ -512,23 +577,30 @@ class Surface:
             vertex_index_conversion[vertex_index] -= 1
         vertex_index_conversion = numpy.cumsum(vertex_index_conversion)
         for triangle_index in range(len(self.triangles)):
-            self.triangles[triangle_index] \
-                = Triangle(map(lambda i: i + int(vertex_index_conversion[i]),
-                               self.triangles[triangle_index].vertex_indices))
+            self.triangles[triangle_index] = Triangle(
+                map(
+                    lambda i: i + int(vertex_index_conversion[i]),
+                    self.triangles[triangle_index].vertex_indices,
+                )
+            )
 
-    def select_vertices(self, vertex_indices: typing.Iterable[int]) \
-            -> typing.List[Vertex]:
+    def select_vertices(
+        self, vertex_indices: typing.Iterable[int]
+    ) -> typing.List[Vertex]:
         return [self.vertices[idx] for idx in vertex_indices]
 
     @staticmethod
-    def unite(surfaces: typing.Iterable['Surface']) -> 'Surface':
+    def unite(surfaces: typing.Iterable["Surface"]) -> "Surface":
         surfaces_iter = iter(surfaces)
         union = copy.deepcopy(next(surfaces_iter))
         for surface in surfaces_iter:
             vertex_index_offset = len(union.vertices)
             union.vertices.extend(surface.vertices)
             union.triangles.extend(
-                Triangle(vertex_idx + vertex_index_offset
-                         for vertex_idx in triangle.vertex_indices)
-                for triangle in surface.triangles)
+                Triangle(
+                    vertex_idx + vertex_index_offset
+                    for vertex_idx in triangle.vertex_indices
+                )
+                for triangle in surface.triangles
+            )
         return union

+ 10 - 17
freesurfer_surface/__main__.py

@@ -10,15 +10,13 @@ def annotation_labels():
     List Labels Stored in Freesurfer's Annotation File
     (i.e., label/lh.aparc.annot)
     """
-    argparser = argparse.ArgumentParser(
-        description=annotation_labels.__doc__.strip())
-    argparser.add_argument('--delimiter', default='\t',
-                           help='default: %(default)r')
-    argparser.add_argument('annotation_file_path')
+    argparser = argparse.ArgumentParser(description=annotation_labels.__doc__.strip())
+    argparser.add_argument("--delimiter", default="\t", help="default: %(default)r")
+    argparser.add_argument("annotation_file_path")
     args = argparser.parse_args()
     annotation = Annotation.read(args.annotation_file_path)
     csv_writer = csv.writer(sys.stdout, delimiter=args.delimiter)
-    csv_writer.writerow(('index', 'color', 'name'))
+    csv_writer.writerow(("index", "color", "name"))
     labels = sorted(annotation.labels.values(), key=lambda l: l.index)
     csv_writer.writerows((l.index, l.hex_color_code, l.name,) for l in labels)
 
@@ -28,16 +26,11 @@ def unite_surfaces():
     Unite Multiple Surfaces in Freesurfer's TriangularSurface Format
     Into a Single TriangularSurface File (i.e., lh.pial, lh.white)
     """
-    argparser = argparse.ArgumentParser(
-        description=unite_surfaces.__doc__.strip())
-    argparser.add_argument('--output',
-                           metavar='OUTPUT_PATH',
-                           dest='output_path',
-                           required=True)
-    argparser.add_argument('input_paths',
-                           metavar='INPUT_PATH',
-                           nargs='+')
+    argparser = argparse.ArgumentParser(description=unite_surfaces.__doc__.strip())
+    argparser.add_argument(
+        "--output", metavar="OUTPUT_PATH", dest="output_path", required=True
+    )
+    argparser.add_argument("input_paths", metavar="INPUT_PATH", nargs="+")
     args = argparser.parse_args()
-    union = Surface.unite(Surface.read_triangular(p)
-                          for p in args.input_paths)
+    union = Surface.unite(Surface.read_triangular(p) for p in args.input_paths)
     union.write_triangular(args.output_path)

+ 23 - 31
setup.py

@@ -2,32 +2,32 @@ import os
 
 import setuptools
 
-with open('README.rst', 'r') as readme:
+with open("README.rst", "r") as readme:
     LONG_DESCRIPTION = readme.read()
 
 setuptools.setup(
-    name='freesurfer-surface',
+    name="freesurfer-surface",
     use_scm_version={
-        'write_to': os.path.join('freesurfer_surface', 'version.py'),
+        "write_to": os.path.join("freesurfer_surface", "version.py"),
         # `version` triggers pylint C0103
-        'write_to_template': "__version__ = '{version}'\n",
+        "write_to_template": "__version__ = '{version}'\n",
     },
     description="Python Library to Read and Write Surface Files"
-                " in Freesurfer's TriangularSurface Format",
+    " in Freesurfer's TriangularSurface Format",
     long_description=LONG_DESCRIPTION,
-    author='Fabian Peter Hammerle',
-    author_email='fabian@hammerle.me',
-    url='https://github.com/fphammerle/freesurfer-surface',
+    author="Fabian Peter Hammerle",
+    author_email="fabian@hammerle.me",
+    url="https://github.com/fphammerle/freesurfer-surface",
     # TODO add license
     keywords=[
-        'brain',
-        'freesurfer',
-        'mesh',
-        'neuroimaging',
-        'reader',
-        'surface',
-        'triangle',
-        'vertex',
+        "brain",
+        "freesurfer",
+        "mesh",
+        "neuroimaging",
+        "reader",
+        "surface",
+        "triangle",
+        "vertex",
     ],
     classifiers=[
         "Development Status :: 3 - Alpha",
@@ -42,21 +42,13 @@ setuptools.setup(
     ],
     packages=setuptools.find_packages(),
     entry_points={
-        'console_scripts': [
-            'freesurfer-annotation-labels = freesurfer_surface.__main__:annotation_labels',
-            'unite-freesurfer-surfaces = freesurfer_surface.__main__:unite_surfaces',
+        "console_scripts": [
+            "freesurfer-annotation-labels = freesurfer_surface.__main__:annotation_labels",
+            "unite-freesurfer-surfaces = freesurfer_surface.__main__:unite_surfaces",
         ],
     },
-    python_requires='>=3.5',
-    install_requires=[
-        'numpy<2',
-    ],
-    setup_requires=[
-        'setuptools_scm',
-    ],
-    tests_require=[
-        'pylint>=2.3.0,<3',
-        'pytest<5',
-        'pytest-cov<3,>=2',
-    ],
+    python_requires=">=3.5",
+    install_requires=["numpy<2",],
+    setup_requires=["setuptools_scm",],
+    tests_require=["pylint>=2.3.0,<3", "pytest<5", "pytest-cov<3,>=2",],
 )

+ 3 - 4
tests/conftest.py

@@ -1,7 +1,6 @@
 import os
 
-SUBJECTS_DIR = os.path.join(os.path.dirname(__file__), 'subjects')
+SUBJECTS_DIR = os.path.join(os.path.dirname(__file__), "subjects")
 
-ANNOTATION_FILE_PATH = os.path.join(SUBJECTS_DIR, 'fabian',
-                                    'label', 'lh.aparc.annot')
-SURFACE_FILE_PATH = os.path.join(SUBJECTS_DIR, 'fabian', 'surf', 'lh.pial')
+ANNOTATION_FILE_PATH = os.path.join(SUBJECTS_DIR, "fabian", "label", "lh.aparc.annot")
+SURFACE_FILE_PATH = os.path.join(SUBJECTS_DIR, "fabian", "surf", "lh.pial")

+ 44 - 17
tests/test_annotation.py

@@ -14,21 +14,48 @@ def test_load_annotation():
     assert annotation.vertex_label_index[93859] == 28
     assert annotation.vertex_label_index[78572] == 0
     assert annotation.vertex_label_index[120377] == 0
-    assert annotation.colortable_path == b'/autofs/space/tanha_002/users/greve' \
-                                         b'/fsdev.build/average/colortable_desikan_killiany.txt'
+    assert (
+        annotation.colortable_path == b"/autofs/space/tanha_002/users/greve"
+        b"/fsdev.build/average/colortable_desikan_killiany.txt"
+    )
     assert len(annotation.labels) == 36
-    assert vars(annotation.labels[0]) == {'index': 0, 'name': 'unknown',
-                                          'red': 25, 'green': 5, 'blue': 25, 'transparency': 0}
-    assert vars(annotation.labels[28]) == {'index': 28, 'name': 'superiorfrontal',
-                                           'red': 20, 'green': 220, 'blue': 160, 'transparency': 0}
-    precentral, = filter(lambda l: l.name == 'precentral',
-                         annotation.labels.values())
-    postcentral, = filter(lambda l: l.name == 'postcentral',
-                          annotation.labels.values())
-    assert vars(precentral) == {'index': 24, 'name': 'precentral',
-                                'red': 60, 'green': 20, 'blue': 220, 'transparency': 0}
-    assert vars(postcentral) == {'index': 22, 'name': 'postcentral',
-                                 'red': 220, 'green': 20, 'blue': 20, 'transparency': 0}
-    superiorfrontal, = filter(lambda l: l.color_code == 10542100,
-                              annotation.labels.values())
-    assert superiorfrontal.name == 'superiorfrontal'
+    assert vars(annotation.labels[0]) == {
+        "index": 0,
+        "name": "unknown",
+        "red": 25,
+        "green": 5,
+        "blue": 25,
+        "transparency": 0,
+    }
+    assert vars(annotation.labels[28]) == {
+        "index": 28,
+        "name": "superiorfrontal",
+        "red": 20,
+        "green": 220,
+        "blue": 160,
+        "transparency": 0,
+    }
+    (precentral,) = filter(lambda l: l.name == "precentral", annotation.labels.values())
+    (postcentral,) = filter(
+        lambda l: l.name == "postcentral", annotation.labels.values()
+    )
+    assert vars(precentral) == {
+        "index": 24,
+        "name": "precentral",
+        "red": 60,
+        "green": 20,
+        "blue": 220,
+        "transparency": 0,
+    }
+    assert vars(postcentral) == {
+        "index": 22,
+        "name": "postcentral",
+        "red": 220,
+        "green": 20,
+        "blue": 20,
+        "transparency": 0,
+    }
+    (superiorfrontal,) = filter(
+        lambda l: l.color_code == 10542100, annotation.labels.values()
+    )
+    assert superiorfrontal.name == "superiorfrontal"

+ 45 - 31
tests/test_label.py

@@ -3,50 +3,64 @@ import pytest
 from freesurfer_surface import Label
 
 
-@pytest.mark.parametrize(('red', 'green', 'blue', 'transparency', 'color_code'), [
-    # pylint: disable=bad-whitespace
-    (220,  20,  20,   0,  1316060),
-    ( 60,  20, 220,   0, 14423100),
-    ( 75,  50, 125,   0,  8204875),
-    ( 20, 220, 160,   0, 10542100),
-])
+@pytest.mark.parametrize(
+    ("red", "green", "blue", "transparency", "color_code"),
+    [
+        # pylint: disable=bad-whitespace
+        (220, 20, 20, 0, 1316060),
+        (60, 20, 220, 0, 14423100),
+        (75, 50, 125, 0, 8204875),
+        (20, 220, 160, 0, 10542100),
+    ],
+)
 def test_color_code(red, green, blue, transparency, color_code):
-    label = Label(index=21, name='name', red=red, green=green,
-                  blue=blue, transparency=transparency)
+    label = Label(
+        index=21,
+        name="name",
+        red=red,
+        green=green,
+        blue=blue,
+        transparency=transparency,
+    )
     assert color_code == label.color_code
 
 
 def test_color_code_unknown():
-    label = Label(index=0, name='unknown', red=21,
-                  green=21, blue=21, transparency=0)
+    label = Label(index=0, name="unknown", red=21, green=21, blue=21, transparency=0)
     assert label.color_code == 0
 
 
-@pytest.mark.parametrize(('red', 'green', 'blue', 'hex_color_code'), [
-    # pylint: disable=bad-whitespace
-    (  0,   0,   0, '#000000'),
-    (255, 255, 255, '#ffffff'),
-    (255,   0,   0, '#ff0000'),
-    (  0, 255,   0, '#00ff00'),
-    (  0,   0, 255, '#0000ff'),
-    (  1,   2,   3, '#010203'),
-    ( 17,  18,  19, '#111213'),
-    (128, 192, 255, '#80c0ff'),
-    ( 20, 220, 160, '#14dca0'),
-])
+@pytest.mark.parametrize(
+    ("red", "green", "blue", "hex_color_code"),
+    [
+        # pylint: disable=bad-whitespace
+        (0, 0, 0, "#000000"),
+        (255, 255, 255, "#ffffff"),
+        (255, 0, 0, "#ff0000"),
+        (0, 255, 0, "#00ff00"),
+        (0, 0, 255, "#0000ff"),
+        (1, 2, 3, "#010203"),
+        (17, 18, 19, "#111213"),
+        (128, 192, 255, "#80c0ff"),
+        (20, 220, 160, "#14dca0"),
+    ],
+)
 def test_hex_color_code(red, green, blue, hex_color_code):
-    label = Label(index=21, name='name', red=red,
-                  green=green, blue=blue, transparency=0)
+    label = Label(
+        index=21, name="name", red=red, green=green, blue=blue, transparency=0
+    )
     assert hex_color_code == label.hex_color_code.lower()
 
 
 def test_str():
-    label = Label(index=24, name='precentral', red=60,
-                  green=20, blue=220, transparency=0)
-    assert str(label) == 'Label(name=precentral, index=24, color=#3c14dc)'
+    label = Label(
+        index=24, name="precentral", red=60, green=20, blue=220, transparency=0
+    )
+    assert str(label) == "Label(name=precentral, index=24, color=#3c14dc)"
 
 
 def test_repr():
-    label = Label(index=24, name='precentral', red=60,
-                  green=20, blue=220, transparency=0)
-    assert repr(label) == 'Label(name=precentral, index=24, color=#3c14dc)'
+    label = Label(
+        index=24, name="precentral", red=60, green=20, blue=220, transparency=0
+    )
+    assert repr(label) == "Label(name=precentral, index=24, color=#3c14dc)"

+ 4 - 2
tests/test_line_segment.py

@@ -15,8 +15,10 @@ def test_eq():
 
 
 def test_repr():
-    assert repr(LineSegment((67018, 67019))) \
-        == 'LineSegment(vertex_indices=(67018, 67019))'
+    assert (
+        repr(LineSegment((67018, 67019)))
+        == "LineSegment(vertex_indices=(67018, 67019))"
+    )
 
 
 def test_adjacent_vertex_indices_1():

+ 37 - 25
tests/test_main.py

@@ -13,34 +13,39 @@ from freesurfer_surface.__main__ import annotation_labels, unite_surfaces
 
 def check_rows(csv_rows: typing.List[str]):
     assert len(csv_rows) == 36 + 1
-    assert csv_rows[0] == ['index', 'color', 'name']
-    assert csv_rows[1] == ['0', '#190519', 'unknown']
-    assert csv_rows[23] == ['22', '#dc1414', 'postcentral']
-    assert csv_rows[25] == ['24', '#3c14dc', 'precentral']
+    assert csv_rows[0] == ["index", "color", "name"]
+    assert csv_rows[1] == ["0", "#190519", "unknown"]
+    assert csv_rows[23] == ["22", "#dc1414", "postcentral"]
+    assert csv_rows[25] == ["24", "#3c14dc", "precentral"]
 
 
 def test_annotation_labels_function(capsys):
-    with unittest.mock.patch('sys.argv', ['', ANNOTATION_FILE_PATH]):
+    with unittest.mock.patch("sys.argv", ["", ANNOTATION_FILE_PATH]):
         annotation_labels()
     out, err = capsys.readouterr()
     assert not err
-    check_rows(list(csv.reader(io.StringIO(out), delimiter='\t')))
+    check_rows(list(csv.reader(io.StringIO(out), delimiter="\t")))
 
 
 def test_annotation_labels_function_delimiter(capsys):
-    with unittest.mock.patch('sys.argv', ['', '--delimiter', ',', ANNOTATION_FILE_PATH]):
+    with unittest.mock.patch(
+        "sys.argv", ["", "--delimiter", ",", ANNOTATION_FILE_PATH]
+    ):
         annotation_labels()
     out, err = capsys.readouterr()
     assert not err
-    check_rows(list(csv.reader(io.StringIO(out), delimiter=',')))
+    check_rows(list(csv.reader(io.StringIO(out), delimiter=",")))
 
 
 def test_annotation_labels_script():
-    proc_info = subprocess.run(['freesurfer-annotation-labels', ANNOTATION_FILE_PATH],
-                               check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    proc_info = subprocess.run(
+        ["freesurfer-annotation-labels", ANNOTATION_FILE_PATH],
+        check=True,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+    )
     assert not proc_info.stderr
-    check_rows(list(csv.reader(io.StringIO(proc_info.stdout.decode()),
-                               delimiter='\t')))
+    check_rows(list(csv.reader(io.StringIO(proc_info.stdout.decode()), delimiter="\t")))
 
 
 def test_unite_surfaces_function(tmpdir, capsys):
@@ -49,11 +54,12 @@ def test_unite_surfaces_function(tmpdir, capsys):
     for i in range(5):
         surface_b.add_vertex(Vertex(i, i, i))
     surface_b.triangles = [Triangle((0, 1, 3)), Triangle((1, 3, 4))]
-    surface_b_path = tmpdir.join('b').strpath
+    surface_b_path = tmpdir.join("b").strpath
     surface_b.write_triangular(surface_b_path)
-    output_path = tmpdir.join('output_path').strpath
-    with unittest.mock.patch('sys.argv', ['', '--output', output_path,
-                                          SURFACE_FILE_PATH, surface_b_path]):
+    output_path = tmpdir.join("output_path").strpath
+    with unittest.mock.patch(
+        "sys.argv", ["", "--output", output_path, SURFACE_FILE_PATH, surface_b_path]
+    ):
         unite_surfaces()
     out, err = capsys.readouterr()
     assert not out
@@ -70,16 +76,22 @@ def test_unite_surfaces_script(tmpdir):
     for i in range(5):
         surface_b.add_vertex(Vertex(i, i, i))
     surface_b.triangles = [Triangle((0, 1, 3)), Triangle((1, 3, 4))]
-    surface_b_path = tmpdir.join('b').strpath
+    surface_b_path = tmpdir.join("b").strpath
     surface_b.write_triangular(surface_b_path)
-    output_path = tmpdir.join('output_path').strpath
-    proc_info = subprocess.run(['unite-freesurfer-surfaces',
-                                '--output', output_path,
-                                SURFACE_FILE_PATH, surface_b_path,
-                                surface_b_path],
-                               check=True,
-                               stdout=subprocess.PIPE,
-                               stderr=subprocess.PIPE)
+    output_path = tmpdir.join("output_path").strpath
+    proc_info = subprocess.run(
+        [
+            "unite-freesurfer-surfaces",
+            "--output",
+            output_path,
+            SURFACE_FILE_PATH,
+            surface_b_path,
+            surface_b_path,
+        ],
+        check=True,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+    )
     assert not proc_info.stdout
     assert not proc_info.stderr
     union = Surface.read_triangular(output_path)

+ 33 - 28
tests/test_polygonal_chain.py

@@ -1,7 +1,10 @@
 import pytest
 
-from freesurfer_surface import (LineSegment, PolygonalChain,
-                                PolygonalChainsNotOverlapingError)
+from freesurfer_surface import (
+    LineSegment,
+    PolygonalChain,
+    PolygonalChainsNotOverlapingError,
+)
 
 
 def test_init():
@@ -25,44 +28,46 @@ def test_eq():
 
 
 def test_repr():
-    assert repr(PolygonalChain([])) \
-        == 'PolygonalChain(vertex_indices=())'
-    assert repr(PolygonalChain((0, 2, 1))) \
-        == 'PolygonalChain(vertex_indices=(0, 2, 1))'
-    assert repr(PolygonalChain((0, 2, 1, 4, 3))) \
-        == 'PolygonalChain(vertex_indices=(0, 2, 1, 4, 3))'
-
-
-@pytest.mark.parametrize(('vertex_indices_a', 'vertex_indices_b', 'expected_vertex_indices'), [
-    ((1, 2, 3), (3, 4), (1, 2, 3, 4)),
-    ((1, 2, 3), (4, 3), (1, 2, 3, 4)),
-    ((3, 2, 1), (3, 4), (4, 3, 2, 1)),
-    ((3, 2, 1), (4, 3), (4, 3, 2, 1)),
-    ((1,), (1,), (1,)),
-    ((1, 2), (1,), (1, 2)),
-    ((1, 2), (2,), (1, 2)),
-    ((0, 3, 1, 5, 2), (3, 5, 2, 0), (3, 5, 2, 0, 3, 1, 5, 2)),
-    ((98792, 98807, 98821), (98792, 98793), (98793, 98792, 98807, 98821)),
-])
+    assert repr(PolygonalChain([])) == "PolygonalChain(vertex_indices=())"
+    assert repr(PolygonalChain((0, 2, 1))) == "PolygonalChain(vertex_indices=(0, 2, 1))"
+    assert (
+        repr(PolygonalChain((0, 2, 1, 4, 3)))
+        == "PolygonalChain(vertex_indices=(0, 2, 1, 4, 3))"
+    )
+
+
+@pytest.mark.parametrize(
+    ("vertex_indices_a", "vertex_indices_b", "expected_vertex_indices"),
+    [
+        ((1, 2, 3), (3, 4), (1, 2, 3, 4)),
+        ((1, 2, 3), (4, 3), (1, 2, 3, 4)),
+        ((3, 2, 1), (3, 4), (4, 3, 2, 1)),
+        ((3, 2, 1), (4, 3), (4, 3, 2, 1)),
+        ((1,), (1,), (1,)),
+        ((1, 2), (1,), (1, 2)),
+        ((1, 2), (2,), (1, 2)),
+        ((0, 3, 1, 5, 2), (3, 5, 2, 0), (3, 5, 2, 0, 3, 1, 5, 2)),
+        ((98792, 98807, 98821), (98792, 98793), (98793, 98792, 98807, 98821)),
+    ],
+)
 def test_connect(vertex_indices_a, vertex_indices_b, expected_vertex_indices):
     chain = PolygonalChain(vertex_indices_a)
     chain.connect(PolygonalChain(vertex_indices_b))
     assert PolygonalChain(expected_vertex_indices) == chain
 
 
-@pytest.mark.parametrize(('vertex_indices_a', 'vertex_indices_b'), [
-    ((1, 2, 3), (2, 4)),
-])
+@pytest.mark.parametrize(
+    ("vertex_indices_a", "vertex_indices_b"), [((1, 2, 3), (2, 4)),]
+)
 def test_connect_fail(vertex_indices_a, vertex_indices_b):
     chain = PolygonalChain(vertex_indices_a)
     with pytest.raises(PolygonalChainsNotOverlapingError):
         chain.connect(PolygonalChain(vertex_indices_b))
 
 
-@pytest.mark.parametrize(('vertex_indices_a', 'vertex_indices_b'), [
-    ((1, 2, 3), ()),
-    ((), (3, 4)),
-])
+@pytest.mark.parametrize(
+    ("vertex_indices_a", "vertex_indices_b"), [((1, 2, 3), ()), ((), (3, 4)),]
+)
 def test_connect_fail_empty(vertex_indices_a, vertex_indices_b):
     chain = PolygonalChain(vertex_indices_a)
     with pytest.raises(Exception):

+ 30 - 38
tests/test_polygonal_circuit.py

@@ -27,22 +27,25 @@ def test_init_invalid_type():
         PolygonalCircuit((0, 1, Vertex(2, 3, 4)))
 
 
-@pytest.mark.parametrize(('source_vertex_indices', 'expected_vertex_indices'), [
-    ((1,), (1,)),
-    ((1, 2), (1, 2)),
-    ((2, 1), (1, 2)),
-    ((1, 2, 3), (1, 2, 3)),
-    ((2, 3, 1), (1, 2, 3)),
-    ((3, 1, 2), (1, 2, 3)),
-    ((1, 3, 2), (1, 2, 3)),
-    ((2, 1, 3), (1, 2, 3)),
-    ((3, 2, 1), (1, 2, 3)),
-    ((1, 2, 3, 5), (1, 2, 3, 5)),
-    ((2, 3, 5, 1), (1, 2, 3, 5)),
-    ((3, 5, 1, 2), (1, 2, 3, 5)),
-    ((2, 1, 5, 3), (1, 2, 3, 5)),
-    ((5, 3, 2, 1), (1, 2, 3, 5)),
-])
+@pytest.mark.parametrize(
+    ("source_vertex_indices", "expected_vertex_indices"),
+    [
+        ((1,), (1,)),
+        ((1, 2), (1, 2)),
+        ((2, 1), (1, 2)),
+        ((1, 2, 3), (1, 2, 3)),
+        ((2, 3, 1), (1, 2, 3)),
+        ((3, 1, 2), (1, 2, 3)),
+        ((1, 3, 2), (1, 2, 3)),
+        ((2, 1, 3), (1, 2, 3)),
+        ((3, 2, 1), (1, 2, 3)),
+        ((1, 2, 3, 5), (1, 2, 3, 5)),
+        ((2, 3, 5, 1), (1, 2, 3, 5)),
+        ((3, 5, 1, 2), (1, 2, 3, 5)),
+        ((2, 1, 5, 3), (1, 2, 3, 5)),
+        ((5, 3, 2, 1), (1, 2, 3, 5)),
+    ],
+)
 def test__normalize(source_vertex_indices, expected_vertex_indices):
     # pylint: disable=protected-access
     circuit = PolygonalCircuit(source_vertex_indices)
@@ -69,31 +72,20 @@ def test_eq_reverse():
 
 
 def test_hash():
-    assert hash(PolygonalCircuit((0, 1, 2))) \
-        == hash(PolygonalCircuit((0, 1, 2)))
-    assert hash(PolygonalCircuit((0, 1, 2))) \
-        == hash(PolygonalCircuit((1, 2, 0)))
-    assert hash(PolygonalCircuit((0, 1, 2))) \
-        == hash(PolygonalCircuit((2, 0, 1)))
-    assert hash(PolygonalCircuit((0, 1, 2))) \
-        != hash(PolygonalCircuit((0, 1, 4)))
-    assert hash(PolygonalCircuit((0, 1, 2))) \
-        != hash(PolygonalCircuit((0, 4, 2)))
-    assert hash(PolygonalCircuit((0, 1, 2))) \
-        != hash(PolygonalCircuit((4, 1, 2)))
+    assert hash(PolygonalCircuit((0, 1, 2))) == hash(PolygonalCircuit((0, 1, 2)))
+    assert hash(PolygonalCircuit((0, 1, 2))) == hash(PolygonalCircuit((1, 2, 0)))
+    assert hash(PolygonalCircuit((0, 1, 2))) == hash(PolygonalCircuit((2, 0, 1)))
+    assert hash(PolygonalCircuit((0, 1, 2))) != hash(PolygonalCircuit((0, 1, 4)))
+    assert hash(PolygonalCircuit((0, 1, 2))) != hash(PolygonalCircuit((0, 4, 2)))
+    assert hash(PolygonalCircuit((0, 1, 2))) != hash(PolygonalCircuit((4, 1, 2)))
 
 
 def test_hash_reverse():
-    assert hash(PolygonalCircuit((0, 1, 2))) \
-        == hash(PolygonalCircuit((2, 1, 0)))
-    assert hash(PolygonalCircuit((0, 1, 2))) \
-        == hash(PolygonalCircuit((0, 2, 1)))
-    assert hash(PolygonalCircuit((0, 1, 2, 4))) \
-        == hash(PolygonalCircuit((4, 2, 1, 0)))
-    assert hash(PolygonalCircuit((0, 1, 2, 4))) \
-        == hash(PolygonalCircuit((1, 0, 4, 2)))
-    assert hash(PolygonalCircuit((0, 1, 2, 4))) \
-        != hash(PolygonalCircuit((1, 4, 0, 2)))
+    assert hash(PolygonalCircuit((0, 1, 2))) == hash(PolygonalCircuit((2, 1, 0)))
+    assert hash(PolygonalCircuit((0, 1, 2))) == hash(PolygonalCircuit((0, 2, 1)))
+    assert hash(PolygonalCircuit((0, 1, 2, 4))) == hash(PolygonalCircuit((4, 2, 1, 0)))
+    assert hash(PolygonalCircuit((0, 1, 2, 4))) == hash(PolygonalCircuit((1, 0, 4, 2)))
+    assert hash(PolygonalCircuit((0, 1, 2, 4))) != hash(PolygonalCircuit((1, 4, 0, 2)))
 
 
 def test_adjacent_vertex_indices_1():

+ 4 - 4
tests/test_setlocale.py

@@ -7,16 +7,16 @@ from freesurfer_surface import UnsupportedLocaleSettingError, setlocale
 
 def test_set():
     system_locale = locale.setlocale(locale.LC_ALL)
-    assert system_locale != 'C'
-    with setlocale('C'):
-        assert locale.setlocale(locale.LC_ALL) == 'C'
+    assert system_locale != "C"
+    with setlocale("C"):
+        assert locale.setlocale(locale.LC_ALL) == "C"
     assert locale.setlocale(locale.LC_ALL) == system_locale
 
 
 def test_unsupported():
     system_locale = locale.setlocale(locale.LC_ALL)
     with pytest.raises(UnsupportedLocaleSettingError):
-        with setlocale('abcdef21'):
+        with setlocale("abcdef21"):
             pass
     assert locale.setlocale(locale.LC_ALL) == system_locale
 

+ 251 - 199
tests/test_surface.py

@@ -5,68 +5,78 @@ import numpy
 import pytest
 
 from conftest import ANNOTATION_FILE_PATH, SURFACE_FILE_PATH
-from freesurfer_surface import (Annotation, LineSegment, PolygonalCircuit,
-                                Surface, Triangle, Vertex, setlocale)
+from freesurfer_surface import (
+    Annotation,
+    LineSegment,
+    PolygonalCircuit,
+    Surface,
+    Triangle,
+    Vertex,
+    setlocale,
+)
 
 # pylint: disable=protected-access
 
 
 def test_read_triangular():
     surface = Surface.read_triangular(SURFACE_FILE_PATH)
-    assert surface.creator == b'fabianpeter'
-    assert surface.creation_datetime \
-        == datetime.datetime(2019, 5, 9, 22, 37, 41)
+    assert surface.creator == b"fabianpeter"
+    assert surface.creation_datetime == datetime.datetime(2019, 5, 9, 22, 37, 41)
     assert len(surface.vertices) == 155622
     assert len(surface.triangles) == 311240
     assert not surface.using_old_real_ras
     assert surface.volume_geometry_info == (
-        b'valid = 1  # volume info valid\n',
-        b'filename = ../mri/filled-pretess255.mgz\n',
-        b'volume = 256 256 256\n',
-        b'voxelsize = 1.000000000000000e+00 1.000000000000000e+00 1.000000000000000e+00\n',
-        b'xras   = -1.000000000000000e+00 0.000000000000000e+00 1.862645149230957e-09\n',
-        b'yras   = 0.000000000000000e+00 -6.655682227574289e-09 -1.000000000000000e+00\n',
-        b'zras   = 0.000000000000000e+00 1.000000000000000e+00 -8.300048648379743e-09\n',
-        b'cras   = -2.773597717285156e+00 1.566547393798828e+01 -7.504364013671875e+00\n')
+        b"valid = 1  # volume info valid\n",
+        b"filename = ../mri/filled-pretess255.mgz\n",
+        b"volume = 256 256 256\n",
+        b"voxelsize = 1.000000000000000e+00 1.000000000000000e+00 1.000000000000000e+00\n",
+        b"xras   = -1.000000000000000e+00 0.000000000000000e+00 1.862645149230957e-09\n",
+        b"yras   = 0.000000000000000e+00 -6.655682227574289e-09 -1.000000000000000e+00\n",
+        b"zras   = 0.000000000000000e+00 1.000000000000000e+00 -8.300048648379743e-09\n",
+        b"cras   = -2.773597717285156e+00 1.566547393798828e+01 -7.504364013671875e+00\n",
+    )
     assert surface.command_lines == [
-        b'mris_remove_intersection ../surf/lh.orig ../surf/lh.orig'
-        b' ProgramVersion: $Name: stable6 $'
-        b'  TimeStamp: 2019/05/09-17:42:36-GMT'
-        b'  BuildTimeStamp: Jan 18 2017 16:38:58'
-        b'  CVS: $Id: mris_remove_intersection.c,v 1.6 2011/03/02 00:04:32 nicks Exp $'
-        b'  User: fabianpeter'
-        b'  Machine: host12345'
-        b'  Platform: Linux'
-        b'  PlatformVersion: 4.15.0-46-generic'
-        b'  CompilerName: GCC'
-        b'  CompilerVersion: 40400'
-        b'  ',
-        b'mris_make_surfaces -orig_white white.preaparc -orig_pial white.preaparc'
-        b' -aseg ../mri/aseg.presurf -mgz -T1 brain.finalsurfs'
-        b' fabian20190509 lh ProgramVersion: $Name:  $'
-        b'  TimeStamp: 2019/05/09-20:27:28-GMT'
-        b'  BuildTimeStamp: Jan 18 2017 16:38:58'
-        b'  CVS: $Id: mris_make_surfaces.c,v 1.164.2.4 2016/12/13 22:26:32 zkaufman Exp $'
-        b'  User: fabianpeter'
-        b'  Machine: host12345'
-        b'  Platform: Linux'
-        b'  PlatformVersion: 4.15.0-46-generic'
-        b'  CompilerName: GCC'
-        b'  CompilerVersion: 40400'
-        b'  ']
+        b"mris_remove_intersection ../surf/lh.orig ../surf/lh.orig"
+        b" ProgramVersion: $Name: stable6 $"
+        b"  TimeStamp: 2019/05/09-17:42:36-GMT"
+        b"  BuildTimeStamp: Jan 18 2017 16:38:58"
+        b"  CVS: $Id: mris_remove_intersection.c,v 1.6 2011/03/02 00:04:32 nicks Exp $"
+        b"  User: fabianpeter"
+        b"  Machine: host12345"
+        b"  Platform: Linux"
+        b"  PlatformVersion: 4.15.0-46-generic"
+        b"  CompilerName: GCC"
+        b"  CompilerVersion: 40400"
+        b"  ",
+        b"mris_make_surfaces -orig_white white.preaparc -orig_pial white.preaparc"
+        b" -aseg ../mri/aseg.presurf -mgz -T1 brain.finalsurfs"
+        b" fabian20190509 lh ProgramVersion: $Name:  $"
+        b"  TimeStamp: 2019/05/09-20:27:28-GMT"
+        b"  BuildTimeStamp: Jan 18 2017 16:38:58"
+        b"  CVS: $Id: mris_make_surfaces.c,v 1.164.2.4 2016/12/13 22:26:32 zkaufman Exp $"
+        b"  User: fabianpeter"
+        b"  Machine: host12345"
+        b"  Platform: Linux"
+        b"  PlatformVersion: 4.15.0-46-generic"
+        b"  CompilerName: GCC"
+        b"  CompilerVersion: 40400"
+        b"  ",
+    ]
 
 
 def test_read_triangular_locale():
-    with setlocale('de_AT.utf8'):
+    with setlocale("de_AT.utf8"):
         surface = Surface.read_triangular(SURFACE_FILE_PATH)
-    assert surface.creation_datetime \
-        == datetime.datetime(2019, 5, 9, 22, 37, 41)
+    assert surface.creation_datetime == datetime.datetime(2019, 5, 9, 22, 37, 41)
 
 
-@pytest.mark.parametrize(('creation_datetime', 'expected_str'), [
-    (datetime.datetime(2019, 5, 9, 22, 37, 41), b'Thu May  9 22:37:41 2019'),
-    (datetime.datetime(2019, 4, 24, 23, 29, 22), b'Wed Apr 24 23:29:22 2019'),
-])
+@pytest.mark.parametrize(
+    ("creation_datetime", "expected_str"),
+    [
+        (datetime.datetime(2019, 5, 9, 22, 37, 41), b"Thu May  9 22:37:41 2019"),
+        (datetime.datetime(2019, 4, 24, 23, 29, 22), b"Wed Apr 24 23:29:22 2019"),
+    ],
+)
 def test_triangular_strftime(creation_datetime, expected_str):
     # pylint: disable=protected-access
     assert expected_str == Surface._triangular_strftime(creation_datetime)
@@ -74,65 +84,71 @@ def test_triangular_strftime(creation_datetime, expected_str):
 
 def test_read_write_triangular_same(tmpdir):
     surface = Surface.read_triangular(SURFACE_FILE_PATH)
-    output_path = tmpdir.join('surface').strpath
-    surface.write_triangular(output_path,
-                             creation_datetime=surface.creation_datetime)
-    with open(output_path, 'rb') as output_file:
-        with open(SURFACE_FILE_PATH, 'rb') as expected_file:
+    output_path = tmpdir.join("surface").strpath
+    surface.write_triangular(output_path, creation_datetime=surface.creation_datetime)
+    with open(output_path, "rb") as output_file:
+        with open(SURFACE_FILE_PATH, "rb") as expected_file:
             assert expected_file.read() == output_file.read()
 
 
 def test_read_write_datetime(tmpdir):
     surface = Surface.read_triangular(SURFACE_FILE_PATH)
     original_creation_datetime = surface.creation_datetime
-    output_path = tmpdir.join('surface').strpath
+    output_path = tmpdir.join("surface").strpath
     surface.write_triangular(output_path)
     assert original_creation_datetime == surface.creation_datetime
     new_surface = Surface.read_triangular(output_path)
     assert new_surface.creation_datetime > original_creation_datetime
     assert datetime.datetime.now() > new_surface.creation_datetime
-    assert (datetime.datetime.now() - new_surface.creation_datetime) \
-        < datetime.timedelta(seconds=20)
+    assert (
+        datetime.datetime.now() - new_surface.creation_datetime
+    ) < datetime.timedelta(seconds=20)
 
 
 def test_write_read_triangular_same(tmpdir):
     expected_surface = Surface()
-    expected_surface.creator = b'pytest'
+    expected_surface.creator = b"pytest"
     expected_surface.creation_datetime = datetime.datetime.now().replace(microsecond=0)
-    expected_surface.vertices = [Vertex(0.0, 0.0, 0.0),
-                                 Vertex(1.0, 2.0, 3.0),
-                                 Vertex(2.0, 4.0, 6.0),
-                                 Vertex(3.0, 5.0, 7.0)]
-    expected_surface.triangles = [Triangle((0, 1, 2)),
-                                  Triangle((0, 1, 3)),
-                                  Triangle((3, 2, 1))]
+    expected_surface.vertices = [
+        Vertex(0.0, 0.0, 0.0),
+        Vertex(1.0, 2.0, 3.0),
+        Vertex(2.0, 4.0, 6.0),
+        Vertex(3.0, 5.0, 7.0),
+    ]
+    expected_surface.triangles = [
+        Triangle((0, 1, 2)),
+        Triangle((0, 1, 3)),
+        Triangle((3, 2, 1)),
+    ]
     expected_surface.using_old_real_ras = False
-    expected_surface.volume_geometry_info = tuple(b'?\n' for _ in range(8))
-    expected_surface.command_lines = [b'?', b'!']
-    output_path = tmpdir.join('surface').strpath
-    expected_surface.write_triangular(output_path,
-                                      creation_datetime=expected_surface.creation_datetime)
+    expected_surface.volume_geometry_info = tuple(b"?\n" for _ in range(8))
+    expected_surface.command_lines = [b"?", b"!"]
+    output_path = tmpdir.join("surface").strpath
+    expected_surface.write_triangular(
+        output_path, creation_datetime=expected_surface.creation_datetime
+    )
     resulted_surface = Surface.read_triangular(output_path)
-    assert numpy.array_equal(expected_surface.vertices,
-                             resulted_surface.vertices)
+    assert numpy.array_equal(expected_surface.vertices, resulted_surface.vertices)
     expected_surface.vertices = resulted_surface.vertices = []
     assert vars(expected_surface) == vars(resulted_surface)
 
 
 def test_write_triangular_same_locale(tmpdir):
     surface = Surface()
-    surface.creator = b'pytest'
-    surface.volume_geometry_info = tuple(b'?' for _ in range(8))
+    surface.creator = b"pytest"
+    surface.volume_geometry_info = tuple(b"?" for _ in range(8))
     creation_datetime = datetime.datetime(2018, 12, 31, 21, 42)
-    output_path = tmpdir.join('surface').strpath
-    with setlocale('de_AT.utf8'):
-        surface.write_triangular(output_path,
-                                 creation_datetime=creation_datetime)
+    output_path = tmpdir.join("surface").strpath
+    with setlocale("de_AT.utf8"):
+        surface.write_triangular(output_path, creation_datetime=creation_datetime)
     resulted_surface = Surface.read_triangular(output_path)
     assert resulted_surface.creation_datetime == creation_datetime
-    with open(output_path, 'rb') as output_file:
-        assert output_file.read().split(b' on ')[1] \
-            .startswith(b'Mon Dec 31 21:42:00 2018\n')
+    with open(output_path, "rb") as output_file:
+        assert (
+            output_file.read()
+            .split(b" on ")[1]
+            .startswith(b"Mon Dec 31 21:42:00 2018\n")
+        )
 
 
 def test_load_annotation():
@@ -155,15 +171,18 @@ def test_add_vertex():
     assert surface.vertices[1].right == pytest.approx(-3.0)
 
 
-@pytest.mark.parametrize('vertices_coords', [
-    ((0, 0, 0), (2, 4, 0), (2, 4, 3)),
-    ((0, 0, 0), (2, 4, 0), (2, 4, 3), (0, 0, 3)),
-    ((1, 1, 0), (3, 5, 0), (3, 5, 3), (1, 1, 3)),
-    ((1, 1, 7), (3, 5, 7), (3, 5, 3), (1, 1, 3)),
-    ((1, 1, 1), (3, 5, 7), (3, 5, 9), (1, 1, 3)),
-    ((3, 5, 7), (1, 1, 1), (1, 1, 3)),
-    ((3, 5, 7), (1, 1, 1), (1, 1, 3), (3, 5, 9)),
-])
+@pytest.mark.parametrize(
+    "vertices_coords",
+    [
+        ((0, 0, 0), (2, 4, 0), (2, 4, 3)),
+        ((0, 0, 0), (2, 4, 0), (2, 4, 3), (0, 0, 3)),
+        ((1, 1, 0), (3, 5, 0), (3, 5, 3), (1, 1, 3)),
+        ((1, 1, 7), (3, 5, 7), (3, 5, 3), (1, 1, 3)),
+        ((1, 1, 1), (3, 5, 7), (3, 5, 9), (1, 1, 3)),
+        ((3, 5, 7), (1, 1, 1), (1, 1, 3)),
+        ((3, 5, 7), (1, 1, 1), (1, 1, 3), (3, 5, 9)),
+    ],
+)
 def test_add_rectangle(vertices_coords):
     surface = Surface()
     for vertex_coords in vertices_coords:
@@ -175,20 +194,22 @@ def test_add_rectangle(vertices_coords):
     assert surface.triangles[1].vertex_indices == (2, 3, 0)
 
 
-@pytest.mark.parametrize(('vertices_coords', 'expected_extra_vertex_coords'), [
-    (((0, 0, 0), (2, 4, 0), (2, 4, 3)), (0, 0, 3)),
-    (((1, 1, 0), (3, 5, 0), (3, 5, 3)), (1, 1, 3)),
-    (((1, 1, 7), (3, 5, 7), (3, 5, 3)), (1, 1, 3)),
-    (((1, 1, 1), (3, 5, 7), (3, 5, 9)), (1, 1, 3)),
-    (((3, 5, 7), (1, 1, 1), (1, 1, 3)), (3, 5, 9)),
-])
+@pytest.mark.parametrize(
+    ("vertices_coords", "expected_extra_vertex_coords"),
+    [
+        (((0, 0, 0), (2, 4, 0), (2, 4, 3)), (0, 0, 3)),
+        (((1, 1, 0), (3, 5, 0), (3, 5, 3)), (1, 1, 3)),
+        (((1, 1, 7), (3, 5, 7), (3, 5, 3)), (1, 1, 3)),
+        (((1, 1, 1), (3, 5, 7), (3, 5, 9)), (1, 1, 3)),
+        (((3, 5, 7), (1, 1, 1), (1, 1, 3)), (3, 5, 9)),
+    ],
+)
 def test_add_rectangle_3(vertices_coords, expected_extra_vertex_coords):
     surface = Surface()
     for vertex_coords in vertices_coords:
         surface.add_vertex(Vertex(*(float(c) for c in vertex_coords)))
     surface.add_rectangle(range(3))
-    assert tuple(surface.vertices[3]) \
-        == pytest.approx(expected_extra_vertex_coords)
+    assert tuple(surface.vertices[3]) == pytest.approx(expected_extra_vertex_coords)
 
 
 def test__triangle_count_by_adjacent_vertex_indices_empty():
@@ -201,18 +222,19 @@ def test__triangle_count_by_adjacent_vertex_indices_none():
     surface.vertices.append(Vertex(1, 0, 0))
     surface.vertices.append(Vertex(2, 0, 0))
     surface.vertices.append(Vertex(3, 0, 0))
-    assert surface._triangle_count_by_adjacent_vertex_indices() \
-        == {0: {}, 1: {}, 2: {}}
+    assert surface._triangle_count_by_adjacent_vertex_indices() == {0: {}, 1: {}, 2: {}}
 
 
 def test__triangle_count_by_adjacent_vertex_indices_single():
     surface = Surface()
-    surface.triangles.append(Triangle([surface.add_vertex(Vertex(i, 0, 0))
-                                       for i in range(3)]))
-    assert surface._triangle_count_by_adjacent_vertex_indices() \
-        == {0: {1: 1, 2: 1},
-            1: {0: 1, 2: 1},
-            2: {0: 1, 1: 1}}
+    surface.triangles.append(
+        Triangle([surface.add_vertex(Vertex(i, 0, 0)) for i in range(3)])
+    )
+    assert surface._triangle_count_by_adjacent_vertex_indices() == {
+        0: {1: 1, 2: 1},
+        1: {0: 1, 2: 1},
+        2: {0: 1, 1: 1},
+    }
 
 
 def test__triangle_count_by_adjacent_vertex_indices_multiple():
@@ -221,26 +243,29 @@ def test__triangle_count_by_adjacent_vertex_indices_multiple():
         surface.add_vertex(Vertex(i, 0, 0))
     surface.triangles.append(Triangle((0, 1, 2)))
     surface.triangles.append(Triangle((3, 1, 2)))
-    assert surface._triangle_count_by_adjacent_vertex_indices() \
-        == {0: {1: 1, 2: 1},
-            1: {0: 1, 2: 2, 3: 1},
-            2: {0: 1, 1: 2, 3: 1},
-            3: {1: 1, 2: 1},
-            4: {}}
+    assert surface._triangle_count_by_adjacent_vertex_indices() == {
+        0: {1: 1, 2: 1},
+        1: {0: 1, 2: 2, 3: 1},
+        2: {0: 1, 1: 2, 3: 1},
+        3: {1: 1, 2: 1},
+        4: {},
+    }
     surface.triangles.append(Triangle((3, 4, 2)))
-    assert surface._triangle_count_by_adjacent_vertex_indices() \
-        == {0: {1: 1, 2: 1},
-            1: {0: 1, 2: 2, 3: 1},
-            2: {0: 1, 1: 2, 3: 2, 4: 1},
-            3: {1: 1, 2: 2, 4: 1},
-            4: {2: 1, 3: 1}}
+    assert surface._triangle_count_by_adjacent_vertex_indices() == {
+        0: {1: 1, 2: 1},
+        1: {0: 1, 2: 2, 3: 1},
+        2: {0: 1, 1: 2, 3: 2, 4: 1},
+        3: {1: 1, 2: 2, 4: 1},
+        4: {2: 1, 3: 1},
+    }
     surface.triangles.append(Triangle((3, 0, 2)))
-    assert surface._triangle_count_by_adjacent_vertex_indices() \
-        == {0: {1: 1, 2: 2, 3: 1},
-            1: {0: 1, 2: 2, 3: 1},
-            2: {0: 2, 1: 2, 3: 3, 4: 1},
-            3: {0: 1, 1: 1, 2: 3, 4: 1},
-            4: {2: 1, 3: 1}}
+    assert surface._triangle_count_by_adjacent_vertex_indices() == {
+        0: {1: 1, 2: 2, 3: 1},
+        1: {0: 1, 2: 2, 3: 1},
+        2: {0: 2, 1: 2, 3: 3, 4: 1},
+        3: {0: 1, 1: 1, 2: 3, 4: 1},
+        4: {2: 1, 3: 1},
+    }
 
 
 def test__triangle_count_by_adjacent_vertex_indices_real():
@@ -248,12 +273,19 @@ def test__triangle_count_by_adjacent_vertex_indices_real():
     counts = surface._triangle_count_by_adjacent_vertex_indices()
     assert len(counts) == len(surface.vertices)
     assert all(counts.values())
-    assert all(count == 2
-               for vertex_counts in counts.values()
-               for count in vertex_counts.values())
-    assert sum(count for vertex_counts in counts.values()
-               for count in vertex_counts.values()) \
+    assert all(
+        count == 2
+        for vertex_counts in counts.values()
+        for count in vertex_counts.values()
+    )
+    assert (
+        sum(
+            count
+            for vertex_counts in counts.values()
+            for count in vertex_counts.values()
+        )
         == len(surface.triangles) * 6
+    )
 
 
 def test_find_borders_none():
@@ -271,8 +303,7 @@ def test_find_borders_single():
 
 def test_find_borders_singles():
     surface = Surface.read_triangular(SURFACE_FILE_PATH)
-    single_indices = [surface.add_vertex(Vertex(i, 21, 42))
-                      for i in range(3)]
+    single_indices = [surface.add_vertex(Vertex(i, 21, 42)) for i in range(3)]
     borders = set(surface.find_borders())
     assert len(borders) == 3
     assert PolygonalCircuit((single_indices[0],)) in borders
@@ -282,8 +313,7 @@ def test_find_borders_singles():
 
 def test_find_borders_single_triangle_simple():
     surface = Surface()
-    vertex_indices = [surface.add_vertex(Vertex(i, 21, 42))
-                      for i in range(3)]
+    vertex_indices = [surface.add_vertex(Vertex(i, 21, 42)) for i in range(3)]
     surface.triangles.append(Triangle(vertex_indices))
     borders = set(surface.find_borders())
     assert len(borders) == 1
@@ -292,8 +322,7 @@ def test_find_borders_single_triangle_simple():
 
 def test_find_borders_single_triangle_real():
     surface = Surface.read_triangular(SURFACE_FILE_PATH)
-    vertex_indices = [surface.add_vertex(Vertex(i, 21, 42))
-                      for i in range(3)]
+    vertex_indices = [surface.add_vertex(Vertex(i, 21, 42)) for i in range(3)]
     surface.triangles.append(Triangle(vertex_indices))
     borders = set(surface.find_borders())
     assert len(borders) == 1
@@ -310,8 +339,7 @@ def test_find_borders_remove_triangle():
 
 def test_find_borders_remove_non_adjacent_triangles():
     surface = Surface.read_triangular(SURFACE_FILE_PATH)
-    triangles = [surface.triangles.pop(),
-                 surface.triangles.pop()]
+    triangles = [surface.triangles.pop(), surface.triangles.pop()]
     borders = set(surface.find_borders())
     assert len(borders) == 2
     assert triangles[0] in borders
@@ -320,8 +348,7 @@ def test_find_borders_remove_non_adjacent_triangles():
 
 def test_find_borders_remove_adjacent_triangles():
     surface = Surface.read_triangular(SURFACE_FILE_PATH)
-    triangles = [surface.triangles.pop(),
-                 surface.triangles.pop()]
+    triangles = [surface.triangles.pop(), surface.triangles.pop()]
     triangles.append(surface.triangles.pop(270682))
     assert triangles[1] == Triangle((136141, 136142, 137076))
     assert triangles[2] == Triangle((136141, 136142, 135263))
@@ -333,45 +360,52 @@ def test_find_borders_remove_adjacent_triangles():
     borders = set(surface.find_borders())
     assert len(borders) == 2
     assert triangles[0] in borders
-    assert PolygonalCircuit((137076, 136141, 135263,
-                             135264, 136142)) in borders
+    assert PolygonalCircuit((137076, 136141, 135263, 135264, 136142)) in borders
     surface.triangles.pop(274320)
     borders = set(surface.find_borders())
     assert len(borders) == 2
     assert PolygonalCircuit((136143, 138007, 138008, 137078)) in borders
-    assert PolygonalCircuit((137076, 136141, 135263,
-                             135264, 136142)) in borders
-
-
-@pytest.mark.parametrize(('label_name', 'expected_border_lens'), [
-    ('precentral', [416]),
-    ('postcentral', [395]),
-    ('medialorbitofrontal', [6, 246]),
-    # ...--2343      2347
-    #          \    /    \
-    #           2345      2348
-    #          /    \    /
-    # ...--2344      2346
-    ('posteriorcingulate', [4, 190]),
-    ('unknown', [3, 390]),
-])
+    assert PolygonalCircuit((137076, 136141, 135263, 135264, 136142)) in borders
+
+
+@pytest.mark.parametrize(
+    ("label_name", "expected_border_lens"),
+    [
+        ("precentral", [416]),
+        ("postcentral", [395]),
+        ("medialorbitofrontal", [6, 246]),
+        # ...--2343      2347
+        #          \    /    \
+        #           2345      2348
+        #          /    \    /
+        # ...--2344      2346
+        ("posteriorcingulate", [4, 190]),
+        ("unknown", [3, 390]),
+    ],
+)
 def test_find_borders_real(label_name, expected_border_lens):
     surface = Surface.read_triangular(SURFACE_FILE_PATH)
     surface.load_annotation_file(ANNOTATION_FILE_PATH)
-    label, = filter(lambda l: l.name == label_name,
-                    surface.annotation.labels.values())
-    surface.triangles = list(filter(
-        lambda t: all(surface.annotation.vertex_label_index[vertex_idx]
-                      == label.index for vertex_idx in t.vertex_indices),
-        surface.triangles,
-    ))
+    (label,) = filter(
+        lambda l: l.name == label_name, surface.annotation.labels.values()
+    )
+    surface.triangles = list(
+        filter(
+            lambda t: all(
+                surface.annotation.vertex_label_index[vertex_idx] == label.index
+                for vertex_idx in t.vertex_indices
+            ),
+            surface.triangles,
+        )
+    )
     surface.remove_unused_vertices()
     borders = list(surface.find_borders())
     border_lens = [len(b.vertex_indices) for b in borders]
     # self-crossing borders may or may not be split into
     # separate polygonal circuits
-    assert sorted(border_lens) == expected_border_lens \
-        or sum(border_lens) == sum(expected_border_lens)
+    assert sorted(border_lens) == expected_border_lens or sum(border_lens) == sum(
+        expected_border_lens
+    )
 
 
 def test__get_vertex_label_index():
@@ -396,46 +430,57 @@ def test__get_vertex_label_index():
 def test__find_label_border_segments():
     surface = Surface.read_triangular(SURFACE_FILE_PATH)
     surface.load_annotation_file(ANNOTATION_FILE_PATH)
-    precentral_label, = filter(lambda l: l.name == 'precentral',
-                               surface.annotation.labels.values())
+    (precentral_label,) = filter(
+        lambda l: l.name == "precentral", surface.annotation.labels.values()
+    )
     # pylint: disable=protected-access
-    border_segments = set(
-        surface._find_label_border_segments(precentral_label))
+    border_segments = set(surface._find_label_border_segments(precentral_label))
     assert len(border_segments) == 417
     assert LineSegment((33450, 32065)) in border_segments
     assert LineSegment((33454, 33450)) in border_segments
     for border_vertex_index in [33450, 33454, 32065]:
-        assert surface.annotation.vertex_label_index[border_vertex_index] == precentral_label.index
+        assert (
+            surface.annotation.vertex_label_index[border_vertex_index]
+            == precentral_label.index
+        )
         for other_vertex_index in [32064, 33449, 33455, 33449, 33455]:
-            assert LineSegment((other_vertex_index, border_vertex_index)) \
+            assert (
+                LineSegment((other_vertex_index, border_vertex_index))
                 not in border_segments
-            assert LineSegment((border_vertex_index, other_vertex_index)) \
+            )
+            assert (
+                LineSegment((border_vertex_index, other_vertex_index))
                 not in border_segments
+            )
 
 
 def test__find_label_border_segments_incomplete_annotation():
     surface = Surface.read_triangular(SURFACE_FILE_PATH)
     surface.load_annotation_file(ANNOTATION_FILE_PATH)
-    precentral_label, = filter(lambda l: l.name == 'precentral',
-                               surface.annotation.labels.values())
+    (precentral_label,) = filter(
+        lambda l: l.name == "precentral", surface.annotation.labels.values()
+    )
     # pylint: disable=protected-access
     assert surface._find_label_border_segments(precentral_label)
-    surface.triangles.append(Triangle([
-        surface.add_vertex(Vertex(0.0, 21.0 * factor, 42.0 * factor))
-        for factor in range(3)
-    ]))
-    border_segments = set(
-        surface._find_label_border_segments(precentral_label))
+    surface.triangles.append(
+        Triangle(
+            [
+                surface.add_vertex(Vertex(0.0, 21.0 * factor, 42.0 * factor))
+                for factor in range(3)
+            ]
+        )
+    )
+    border_segments = set(surface._find_label_border_segments(precentral_label))
     assert len(border_segments) == 417
 
 
 def test_find_label_border_polygonal_chains():
     surface = Surface.read_triangular(SURFACE_FILE_PATH)
     surface.load_annotation_file(ANNOTATION_FILE_PATH)
-    precentral_label, = filter(lambda l: l.name == 'precentral',
-                               surface.annotation.labels.values())
-    border_chain, = surface.find_label_border_polygonal_chains(
-        precentral_label)
+    (precentral_label,) = filter(
+        lambda l: l.name == "precentral", surface.annotation.labels.values()
+    )
+    (border_chain,) = surface.find_label_border_polygonal_chains(precentral_label)
     vertex_indices = list(border_chain.vertex_indices)
     assert len(vertex_indices) == 418
     min_index = vertex_indices.index(min(vertex_indices))
@@ -461,8 +506,9 @@ def test__unused_vertices():
 def test__unused_vertices_real():
     surface = Surface.read_triangular(SURFACE_FILE_PATH)
     assert not surface._unused_vertices()
-    surface.triangles = list(filter(lambda t: 42 not in t.vertex_indices,
-                                    surface.triangles))
+    surface.triangles = list(
+        filter(lambda t: 42 not in t.vertex_indices, surface.triangles)
+    )
     assert surface._unused_vertices() == {42}
 
 
@@ -534,31 +580,36 @@ def test_remove_unused_vertices_single():
     assert len(surface.vertices) == 155622
     assert len(surface.triangles) == 311240
     assert surface.triangles[-1] == Triangle((136143, 138007, 137078))
-    surface.triangles = list(filter(lambda t: 42 not in t.vertex_indices,
-                                    surface.triangles))
+    surface.triangles = list(
+        filter(lambda t: 42 not in t.vertex_indices, surface.triangles)
+    )
     assert surface._unused_vertices() == {42}
     surface.remove_unused_vertices()
     assert len(surface.vertices) == 155622 - 1
     assert len(surface.triangles) == 311240 - 7
     assert surface.triangles[-1] == Triangle((136142, 138006, 137077))
-    assert all(vertex_index < len(surface.vertices)
-               for triangle in surface.triangles
-               for vertex_index in triangle.vertex_indices)
+    assert all(
+        vertex_index < len(surface.vertices)
+        for triangle in surface.triangles
+        for vertex_index in triangle.vertex_indices
+    )
 
 
 def test_select_vertices():
     surface = Surface()
     for i in range(4):
         surface.add_vertex(Vertex(i, i, i))
-    assert numpy.allclose(surface.select_vertices([2, 1]),
-                          [surface.vertices[2], surface.vertices[1]])
-    assert numpy.allclose(surface.select_vertices([3, 2]),
-                          [surface.vertices[3], surface.vertices[2]])
-    assert numpy.allclose(surface.select_vertices((3, 2)),
-                          [[3, 3, 3], [2, 2, 2]])
-    assert numpy.allclose(surface.select_vertices(filter(lambda i: i % 2 == 1,
-                                                         range(4))),
-                          [[1, 1, 1], [3, 3, 3]])
+    assert numpy.allclose(
+        surface.select_vertices([2, 1]), [surface.vertices[2], surface.vertices[1]]
+    )
+    assert numpy.allclose(
+        surface.select_vertices([3, 2]), [surface.vertices[3], surface.vertices[2]]
+    )
+    assert numpy.allclose(surface.select_vertices((3, 2)), [[3, 3, 3], [2, 2, 2]])
+    assert numpy.allclose(
+        surface.select_vertices(filter(lambda i: i % 2 == 1, range(4))),
+        [[1, 1, 1], [3, 3, 3]],
+    )
 
 
 def test_unite_2():
@@ -621,7 +672,8 @@ def test_unite_real():
     assert union.triangles[:-2] == surface_a.triangles
     assert union.triangles[-2:] == [
         Triangle((155622, 155623, 155625)),
-        Triangle((155623, 155625, 155626))]
+        Triangle((155623, 155625, 155626)),
+    ]
     assert union.creator == surface_a.creator
     assert union.creation_datetime == surface_a.creation_datetime
     assert union.using_old_real_ras == surface_a.using_old_real_ras

+ 1 - 1
tests/test_triangle.py

@@ -23,7 +23,7 @@ def test_eq():
 
 
 def test_repr():
-    assert repr(Triangle((0, 1, 2))) == 'Triangle(vertex_indices=(0, 1, 2))'
+    assert repr(Triangle((0, 1, 2))) == "Triangle(vertex_indices=(0, 1, 2))"
 
 
 def test_adjacent_vertex_indices_1():

+ 34 - 29
tests/test_vertex.py

@@ -21,12 +21,13 @@ def test_init_kwargs():
 
 def test_repr():
     vertex = Vertex(right=-4.0, superior=21.42, anterior=0.5)
-    assert repr(vertex) == 'Vertex(right=-4.0, anterior=0.5, superior=21.42)'
+    assert repr(vertex) == "Vertex(right=-4.0, anterior=0.5, superior=21.42)"
 
 
 def test_add():
-    assert Vertex(-1.5, 4, 2) + Vertex(2, -4.5, 3) \
-        == pytest.approx(Vertex(0.5, -0.5, 5))
+    assert Vertex(-1.5, 4, 2) + Vertex(2, -4.5, 3) == pytest.approx(
+        Vertex(0.5, -0.5, 5)
+    )
 
 
 def test_mult():
@@ -36,32 +37,36 @@ def test_mult():
 def test_vars():
     attrs = vars(Vertex(-1.5, 4, 2))
     assert len(attrs) == 3
-    assert attrs['right'] == pytest.approx(-1.5)
-    assert attrs['anterior'] == pytest.approx(4)
-    assert attrs['superior'] == pytest.approx(2)
+    assert attrs["right"] == pytest.approx(-1.5)
+    assert attrs["anterior"] == pytest.approx(4)
+    assert attrs["superior"] == pytest.approx(2)
 
 
-@pytest.mark.parametrize(('vertex_a', 'vertex_b', 'expected_distance_mm'), [
-    (Vertex(0, 0, 0), Vertex(0, 0, 0), 0),
-    (Vertex(0, 0, 0), Vertex(1, 0, 0), 1),
-    (Vertex(0, 0, 0), Vertex(0, 1, 0), 1),
-    (Vertex(0, 0, 0), Vertex(0, 0, 1), 1),
-    (Vertex(0, 0, 0), Vertex(1, 1, 0), 2**(1/2)),
-    (Vertex(0, 0, 0), Vertex(1, 1, 1), 3**(1/2)),
-    (Vertex(1, 2, 3), Vertex(2, 3, 4), 3**(1/2)),
-    (Vertex(1, 2, 3), Vertex(5, 8, -1), (16+36+16)**(1/2)),
-    (Vertex(0, 0, 0), [Vertex(0, 0, 1), Vertex(0, 0, 2)], [1, 2]),
-    (Vertex(0, 0, 0), (Vertex(0, 0, 1), Vertex(0, 0, 2)), [1, 2]),
-    (Vertex(0, 0, 0),
-     numpy.vstack((Vertex(0, 0, 1), Vertex(0, 0, 2))),
-     [1, 2]),
-    (Vertex(1, 2, 3),
-     (Vertex(2, 3, 4), Vertex(3, 4, 5)),
-     [3**(1/2), 12**(1/2)]),
-    (Vertex(1, 2, 3),
-     (Vertex(2, 3, 4), Vertex(3, 4, 5), Vertex(3, 4, 6)),
-     [3**(1/2), 12**(1/2), 17**(1/2)]),
-])
+@pytest.mark.parametrize(
+    ("vertex_a", "vertex_b", "expected_distance_mm"),
+    [
+        (Vertex(0, 0, 0), Vertex(0, 0, 0), 0),
+        (Vertex(0, 0, 0), Vertex(1, 0, 0), 1),
+        (Vertex(0, 0, 0), Vertex(0, 1, 0), 1),
+        (Vertex(0, 0, 0), Vertex(0, 0, 1), 1),
+        (Vertex(0, 0, 0), Vertex(1, 1, 0), 2 ** (1 / 2)),
+        (Vertex(0, 0, 0), Vertex(1, 1, 1), 3 ** (1 / 2)),
+        (Vertex(1, 2, 3), Vertex(2, 3, 4), 3 ** (1 / 2)),
+        (Vertex(1, 2, 3), Vertex(5, 8, -1), (16 + 36 + 16) ** (1 / 2)),
+        (Vertex(0, 0, 0), [Vertex(0, 0, 1), Vertex(0, 0, 2)], [1, 2]),
+        (Vertex(0, 0, 0), (Vertex(0, 0, 1), Vertex(0, 0, 2)), [1, 2]),
+        (Vertex(0, 0, 0), numpy.vstack((Vertex(0, 0, 1), Vertex(0, 0, 2))), [1, 2]),
+        (
+            Vertex(1, 2, 3),
+            (Vertex(2, 3, 4), Vertex(3, 4, 5)),
+            [3 ** (1 / 2), 12 ** (1 / 2)],
+        ),
+        (
+            Vertex(1, 2, 3),
+            (Vertex(2, 3, 4), Vertex(3, 4, 5), Vertex(3, 4, 6)),
+            [3 ** (1 / 2), 12 ** (1 / 2), 17 ** (1 / 2)],
+        ),
+    ],
+)
 def test_distance(vertex_a, vertex_b, expected_distance_mm):
-    assert vertex_a.distance_mm(vertex_b) \
-        == pytest.approx(expected_distance_mm)
+    assert vertex_a.distance_mm(vertex_b) == pytest.approx(expected_distance_mm)