|
27 | 27 |
|
28 | 28 | from io import BytesIO
|
29 | 29 | import math
|
| 30 | +from typing import TYPE_CHECKING |
30 | 31 | from xml.etree.ElementTree import Element, ElementTree, SubElement
|
31 | 32 |
|
32 | 33 | from PIL import Image
|
33 | 34 |
|
34 | 35 | import openslide
|
35 | 36 |
|
| 37 | +if TYPE_CHECKING: |
| 38 | + # Python 3.10+ |
| 39 | + from typing import TypeGuard |
| 40 | + |
36 | 41 |
|
37 | 42 | class DeepZoomGenerator:
|
38 | 43 | """Generates Deep Zoom tiles and metadata."""
|
@@ -104,7 +109,8 @@ def __init__(
|
104 | 109 | while z_size[0] > 1 or z_size[1] > 1:
|
105 | 110 | z_size = tuple(max(1, int(math.ceil(z / 2))) for z in z_size)
|
106 | 111 | z_dimensions.append(z_size)
|
107 |
| - self._z_dimensions = tuple(reversed(z_dimensions)) |
| 112 | + # Narrow the type, for self.level_dimensions |
| 113 | + self._z_dimensions = self._pairs_from_n_tuples(tuple(reversed(z_dimensions))) |
108 | 114 |
|
109 | 115 | # Tile
|
110 | 116 | def tiles(z_lim: int) -> int:
|
@@ -161,7 +167,7 @@ def level_tiles(self) -> tuple[tuple[int, int], ...]:
|
161 | 167 | return self._t_dimensions
|
162 | 168 |
|
163 | 169 | @property
|
164 |
| - def level_dimensions(self) -> tuple[tuple[int, ...], ...]: |
| 170 | + def level_dimensions(self) -> tuple[tuple[int, int], ...]: |
165 | 171 | """A list of (pixels_x, pixels_y) tuples for each Deep Zoom level."""
|
166 | 172 | return self._z_dimensions
|
167 | 173 |
|
@@ -255,6 +261,18 @@ def _l_from_z(self, dz_level: int, z: int) -> float:
|
255 | 261 | def _z_from_t(self, t: int) -> int:
|
256 | 262 | return self._z_t_downsample * t
|
257 | 263 |
|
| 264 | + @staticmethod |
| 265 | + def _pairs_from_n_tuples( |
| 266 | + tuples: tuple[tuple[int, ...], ...] |
| 267 | + ) -> tuple[tuple[int, int], ...]: |
| 268 | + def all_pairs( |
| 269 | + tuples: tuple[tuple[int, ...], ...] |
| 270 | + ) -> TypeGuard[tuple[tuple[int, int], ...]]: |
| 271 | + return all(len(t) == 2 for t in tuples) |
| 272 | + |
| 273 | + assert all_pairs(tuples) |
| 274 | + return tuples |
| 275 | + |
258 | 276 | def get_tile_coordinates(
|
259 | 277 | self, level: int, address: tuple[int, int]
|
260 | 278 | ) -> tuple[tuple[int, int], int, tuple[int, int]]:
|
|
0 commit comments