dlup 0.3.26__tar.gz → 0.3.28__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. {dlup-0.3.26 → dlup-0.3.28}/MANIFEST.in +2 -1
  2. {dlup-0.3.26/dlup.egg-info → dlup-0.3.28}/PKG-INFO +22 -2
  3. {dlup-0.3.26 → dlup-0.3.28}/dlup/__init__.py +3 -5
  4. {dlup-0.3.26 → dlup-0.3.28}/dlup/_image.py +46 -24
  5. {dlup-0.3.26 → dlup-0.3.28}/dlup/_region.py +2 -3
  6. {dlup-0.3.26 → dlup-0.3.28}/dlup/annotations.py +135 -90
  7. dlup-0.3.28/dlup/backends/__init__.py +1 -0
  8. {dlup-0.3.26/dlup/experimental_backends → dlup-0.3.28/dlup/backends}/common.py +13 -14
  9. dlup-0.3.28/dlup/background.py +147 -0
  10. dlup-0.3.26/dlup/background.py → dlup-0.3.28/dlup/background_deprecated.py +39 -149
  11. {dlup-0.3.26 → dlup-0.3.28}/dlup/cli/__init__.py +2 -3
  12. {dlup-0.3.26 → dlup-0.3.28}/dlup/cli/mask.py +14 -15
  13. {dlup-0.3.26 → dlup-0.3.28}/dlup/cli/wsi.py +14 -13
  14. {dlup-0.3.26 → dlup-0.3.28}/dlup/data/dataset.py +169 -85
  15. {dlup-0.3.26 → dlup-0.3.28}/dlup/data/experimental/dataset.py +14 -12
  16. {dlup-0.3.26 → dlup-0.3.28}/dlup/data/transforms.py +54 -32
  17. {dlup-0.3.26 → dlup-0.3.28}/dlup/experimental_backends/__init__.py +2 -2
  18. {dlup-0.3.26 → dlup-0.3.28}/dlup/experimental_backends/openslide_backend.py +4 -4
  19. {dlup-0.3.26 → dlup-0.3.28}/dlup/experimental_backends/pyvips_backend.py +9 -8
  20. {dlup-0.3.26 → dlup-0.3.28}/dlup/experimental_backends/tifffile_backend.py +7 -4
  21. {dlup-0.3.26 → dlup-0.3.28}/dlup/tiling.py +18 -12
  22. dlup-0.3.28/dlup/tools.py +83 -0
  23. dlup-0.3.28/dlup/types.py +17 -0
  24. {dlup-0.3.26 → dlup-0.3.28}/dlup/utils/__init__.py +2 -10
  25. {dlup-0.3.26 → dlup-0.3.28}/dlup/utils/image.py +1 -1
  26. {dlup-0.3.26 → dlup-0.3.28}/dlup/utils/imports.py +3 -3
  27. {dlup-0.3.26 → dlup-0.3.28}/dlup/utils/mask.py +28 -15
  28. {dlup-0.3.26 → dlup-0.3.28}/dlup/utils/pyvips_utils.py +8 -4
  29. dlup-0.3.28/dlup/utils/tifffile_utils.py +144 -0
  30. {dlup-0.3.26 → dlup-0.3.28}/dlup/viz/plotting.py +9 -4
  31. {dlup-0.3.26 → dlup-0.3.28}/dlup/writers.py +17 -10
  32. {dlup-0.3.26 → dlup-0.3.28/dlup.egg-info}/PKG-INFO +22 -2
  33. {dlup-0.3.26 → dlup-0.3.28}/dlup.egg-info/SOURCES.txt +15 -3
  34. {dlup-0.3.26 → dlup-0.3.28}/dlup.egg-info/requires.txt +1 -1
  35. {dlup-0.3.26 → dlup-0.3.28}/docs/conf.py +5 -1
  36. {dlup-0.3.26 → dlup-0.3.28}/pyproject.toml +0 -3
  37. {dlup-0.3.26 → dlup-0.3.28}/setup.cfg +4 -1
  38. {dlup-0.3.26 → dlup-0.3.28}/setup.py +1 -1
  39. dlup-0.3.28/tests/backends/__init__.py +0 -0
  40. dlup-0.3.28/tests/backends/test_common.py +115 -0
  41. dlup-0.3.28/tests/backends/test_tifffile_backend.py +62 -0
  42. {dlup-0.3.26 → dlup-0.3.28}/tests/common.py +5 -2
  43. {dlup-0.3.26 → dlup-0.3.28}/tests/conftest.py +2 -2
  44. dlup-0.3.28/tests/infer_ann.py +3 -0
  45. {dlup-0.3.26 → dlup-0.3.28}/tests/test_annotations.py +4 -2
  46. dlup-0.3.28/tests/test_cli.py +39 -0
  47. {dlup-0.3.26 → dlup-0.3.28}/tests/test_dataset.py +9 -4
  48. {dlup-0.3.26 → dlup-0.3.28}/tests/test_image.py +21 -14
  49. dlup-0.3.28/tests/test_logging.py +44 -0
  50. {dlup-0.3.26 → dlup-0.3.28}/tests/test_tiling.py +8 -8
  51. dlup-0.3.28/tests/test_transforms.py +76 -0
  52. {dlup-0.3.26 → dlup-0.3.28}/tests/test_writers.py +4 -1
  53. dlup-0.3.28/tests/utils/__init__.py +0 -0
  54. dlup-0.3.28/tests/utils/test_imports.py +24 -0
  55. {dlup-0.3.26 → dlup-0.3.28}/tests/utils/test_pyvips.py +0 -1
  56. dlup-0.3.28/tests/utils/test_tifffile.py +60 -0
  57. dlup-0.3.28/tests/utils/test_utils.py +32 -0
  58. dlup-0.3.26/dlup/tools.py +0 -71
  59. dlup-0.3.26/dlup/types.py +0 -15
  60. dlup-0.3.26/dlup/utils/tifffile_utils.py +0 -92
  61. dlup-0.3.26/tests/new_test.py +0 -101
  62. {dlup-0.3.26 → dlup-0.3.28}/CONTRIBUTING.rst +0 -0
  63. {dlup-0.3.26 → dlup-0.3.28}/LICENSE +0 -0
  64. {dlup-0.3.26 → dlup-0.3.28}/README.md +0 -0
  65. {dlup-0.3.26 → dlup-0.3.28}/dlup/_exceptions.py +0 -0
  66. {dlup-0.3.26 → dlup-0.3.28}/dlup/data/__init__.py +0 -0
  67. {dlup-0.3.26 → dlup-0.3.28}/dlup/data/experimental/__init__.py +0 -0
  68. {dlup-0.3.26 → dlup-0.3.28}/dlup/logging.py +0 -0
  69. /dlup-0.3.26/tests/__init__.py → /dlup-0.3.28/dlup/py.typed +0 -0
  70. {dlup-0.3.26 → dlup-0.3.28}/dlup/viz/__init__.py +0 -0
  71. {dlup-0.3.26 → dlup-0.3.28}/dlup.egg-info/dependency_links.txt +0 -0
  72. {dlup-0.3.26 → dlup-0.3.28}/dlup.egg-info/entry_points.txt +0 -0
  73. {dlup-0.3.26 → dlup-0.3.28}/dlup.egg-info/not-zip-safe +0 -0
  74. {dlup-0.3.26 → dlup-0.3.28}/dlup.egg-info/top_level.txt +0 -0
  75. {dlup-0.3.26 → dlup-0.3.28}/docs/Makefile +0 -0
  76. {dlup-0.3.26 → dlup-0.3.28}/docs/backends.rst +0 -0
  77. {dlup-0.3.26 → dlup-0.3.28}/docs/cli.rst +0 -0
  78. {dlup-0.3.26 → dlup-0.3.28}/docs/contributing.rst +0 -0
  79. {dlup-0.3.26 → dlup-0.3.28}/docs/examples/dataset_examples.rst +0 -0
  80. {dlup-0.3.26 → dlup-0.3.28}/docs/examples/tile_directory.rst +0 -0
  81. {dlup-0.3.26 → dlup-0.3.28}/docs/examples.rst +0 -0
  82. {dlup-0.3.26 → dlup-0.3.28}/docs/img/checkerboard.png +0 -0
  83. {dlup-0.3.26 → dlup-0.3.28}/docs/img/dataset_example.png +0 -0
  84. {dlup-0.3.26 → dlup-0.3.28}/docs/img/dataset_example2.png +0 -0
  85. {dlup-0.3.26 → dlup-0.3.28}/docs/img/overflow.png +0 -0
  86. {dlup-0.3.26 → dlup-0.3.28}/docs/img/skip.png +0 -0
  87. {dlup-0.3.26 → dlup-0.3.28}/docs/index.rst +0 -0
  88. {dlup-0.3.26 → dlup-0.3.28}/docs/installation.rst +0 -0
  89. {dlup-0.3.26 → dlup-0.3.28}/docs/make.bat +0 -0
  90. {dlup-0.3.26 → dlup-0.3.28}/docs/quickstart.rst +0 -0
  91. {dlup-0.3.26 → dlup-0.3.28}/docs/tiling.rst +0 -0
  92. {dlup-0.3.26 → dlup-0.3.28}/docs/writers.rst +0 -0
  93. {dlup-0.3.26/tests/utils → dlup-0.3.28/tests}/__init__.py +0 -0
  94. {dlup-0.3.26 → dlup-0.3.28}/tests/files/103S.json +0 -0
@@ -1,9 +1,10 @@
1
1
  include CONTRIBUTING.rst
2
2
  include LICENSE
3
3
  include README.md
4
+ include dlup/py.typed
4
5
 
5
6
  recursive-include tests *
6
7
  recursive-exclude * __pycache__
7
8
  recursive-exclude * *.py[co]
8
9
 
9
- recursive-include docs *.rst *.md conf.py Makefile make.bat *.jpg *.png *.gif *.typed
10
+ recursive-include docs *.rst *.md conf.py Makefile make.bat *.jpg *.png *.gif
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dlup
3
- Version: 0.3.26
3
+ Version: 0.3.28
4
4
  Home-page: https://github.com/NKI-AI/dlup
5
5
  Author: Jonas Teuwen
6
6
  Author-email: j.teuwen@nki.nl
@@ -15,8 +15,28 @@ Classifier: Programming Language :: Python :: 3.10
15
15
  Classifier: Programming Language :: Python :: 3.11
16
16
  Requires-Python: >=3.10
17
17
  Description-Content-Type: text/markdown
18
- Provides-Extra: dev
19
18
  License-File: LICENSE
19
+ Requires-Dist: numpy>=1.21
20
+ Requires-Dist: scikit-image>=0.19
21
+ Requires-Dist: tifftools
22
+ Requires-Dist: tifffile>=2023.8.12
23
+ Requires-Dist: pyvips>=2.2.1
24
+ Requires-Dist: tqdm
25
+ Requires-Dist: pillow>=9.2.0
26
+ Requires-Dist: openslide-python
27
+ Requires-Dist: opencv-python>=4.8.1.78
28
+ Requires-Dist: shapely>=2.0.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest; extra == "dev"
31
+ Requires-Dist: mypy>=1.4.1; extra == "dev"
32
+ Requires-Dist: pytest-mock; extra == "dev"
33
+ Requires-Dist: sphinx_copybutton; extra == "dev"
34
+ Requires-Dist: numpydoc; extra == "dev"
35
+ Requires-Dist: myst_parser; extra == "dev"
36
+ Requires-Dist: sphinx-book-theme; extra == "dev"
37
+ Requires-Dist: pylint; extra == "dev"
38
+ Requires-Dist: pydantic>=2.1.1; extra == "dev"
39
+ Requires-Dist: types-requests; extra == "dev"
20
40
 
21
41
  # Deep Learning Utilities for Pathology
22
42
  [![pypi](https://img.shields.io/pypi/v/dlup.svg)](https://pypi.python.org/pypi/dlup)
@@ -1,13 +1,11 @@
1
- # coding=utf-8
2
- # Copyright (c) dlup contributors
3
- """Top-level package for dlup."""
1
+ # Copyright (c) dlup contributors"""Top-level package for dlup."""
4
2
 
5
- from ._exceptions import DlupError, UnsupportedSlideError
3
+ from ._exceptions import UnsupportedSlideError
6
4
  from ._image import SlideImage
7
5
  from ._region import BoundaryMode, RegionView
8
6
 
9
7
  __author__ = """dlup contributors"""
10
8
  __email__ = "j.teuwen@nki.nl"
11
- __version__ = "0.3.26"
9
+ __version__ = "0.3.28"
12
10
 
13
11
  __all__ = ("SlideImage", "RegionView", "UnsupportedSlideError", "BoundaryMode")
@@ -1,4 +1,3 @@
1
- # coding=utf-8
2
1
  # Copyright (c) dlup contributors
3
2
 
4
3
  """Whole slide image access objects.
@@ -13,17 +12,19 @@ import errno
13
12
  import os
14
13
  import pathlib
15
14
  from enum import IntEnum
16
- from typing import Callable, Type, TypeVar, cast
15
+ from types import TracebackType
16
+ from typing import Any, Literal, Optional, Type, TypeVar, cast
17
17
 
18
- import numpy as np # type: ignore
19
- import openslide # type: ignore
18
+ import numpy as np
19
+ import numpy.typing as npt
20
20
  import PIL
21
- import PIL.Image # type: ignore
21
+ import PIL.Image
22
22
 
23
23
  from dlup import UnsupportedSlideError
24
24
  from dlup._region import BoundaryMode, RegionView
25
- from dlup.experimental_backends import AbstractSlideBackend, ImageBackend
26
- from dlup.types import GenericFloatArray, GenericIntArray, GenericNumber, PathLike
25
+ from dlup.backends.common import AbstractSlideBackend
26
+ from dlup.experimental_backends import ImageBackend # type: ignore
27
+ from dlup.types import GenericFloatArray, GenericIntArray, GenericNumber, GenericNumberArray, PathLike
27
28
  from dlup.utils.image import check_if_mpp_is_valid
28
29
 
29
30
  _Box = tuple[GenericNumber, GenericNumber, GenericNumber, GenericNumber]
@@ -42,7 +43,12 @@ class Resampling(IntEnum):
42
43
  class _SlideImageRegionView(RegionView):
43
44
  """Represents an image view tied to a slide image."""
44
45
 
45
- def __init__(self, wsi: _TSlideImage, scaling: GenericNumber, boundary_mode: BoundaryMode | None = None):
46
+ def __init__(
47
+ self,
48
+ wsi: _TSlideImage,
49
+ scaling: GenericNumber,
50
+ boundary_mode: BoundaryMode | None = None,
51
+ ):
46
52
  """Initialize with a slide image object and the scaling level."""
47
53
  # Always call the parent init
48
54
  super().__init__(boundary_mode=boundary_mode)
@@ -66,7 +72,9 @@ class _SlideImageRegionView(RegionView):
66
72
  return self._wsi.read_region((x, y), self._scaling, (w, h))
67
73
 
68
74
 
69
- def _clip2size(a: np.ndarray, size: tuple[GenericNumber, GenericNumber]) -> np.ndarray:
75
+ def _clip2size(
76
+ a: npt.NDArray[np.int_ | np.float_], size: tuple[GenericNumber, GenericNumber]
77
+ ) -> npt.NDArray[np.int_ | np.float_]:
70
78
  """Clip values from 0 to size boundaries."""
71
79
  return np.clip(a, (0, 0), size)
72
80
 
@@ -92,7 +100,7 @@ class SlideImage:
92
100
  >>> wsi = dlup.SlideImage.from_file_path('path/to/slide.svs')
93
101
  """
94
102
 
95
- def __init__(self, wsi: AbstractSlideBackend, identifier: str | None = None, **kwargs):
103
+ def __init__(self, wsi: AbstractSlideBackend, identifier: str | None = None, **kwargs: Any) -> None:
96
104
  """Initialize a whole slide image and validate its properties."""
97
105
  self._wsi = wsi
98
106
  self._identifier = identifier
@@ -111,20 +119,26 @@ class SlideImage:
111
119
 
112
120
  if self._wsi.spacing is None:
113
121
  raise UnsupportedSlideError(
114
- f"The spacing of {identifier} cannot be derived from image and is not explicitly set in the `overwrite_mpp` parameter."
122
+ f"The spacing of {identifier} cannot be derived from image and is "
123
+ "not explicitly set in the `overwrite_mpp` parameter."
115
124
  )
116
125
 
117
126
  check_if_mpp_is_valid(*self._wsi.spacing)
118
127
  self._avg_native_mpp = (float(self._wsi.spacing[0]) + float(self._wsi.spacing[1])) / 2
119
128
 
120
- def close(self):
129
+ def close(self) -> None:
121
130
  """Close the underlying image."""
122
131
  self._wsi.close()
123
132
 
124
- def __enter__(self):
133
+ def __enter__(self) -> "SlideImage":
125
134
  return self
126
135
 
127
- def __exit__(self, exc_type, exc_val, exc_tb):
136
+ def __exit__(
137
+ self,
138
+ exc_type: Optional[Type[BaseException]],
139
+ exc_val: Optional[BaseException],
140
+ exc_tb: Optional[TracebackType],
141
+ ) -> Literal[False]:
128
142
  self.close()
129
143
  return False
130
144
 
@@ -133,8 +147,8 @@ class SlideImage:
133
147
  cls: Type[_TSlideImage],
134
148
  wsi_file_path: PathLike,
135
149
  identifier: str | None = None,
136
- backend: str | Callable = ImageBackend.PYVIPS,
137
- **kwargs,
150
+ backend: ImageBackend = ImageBackend.PYVIPS,
151
+ **kwargs: Any,
138
152
  ) -> _TSlideImage:
139
153
  wsi_file_path = pathlib.Path(wsi_file_path)
140
154
 
@@ -152,9 +166,9 @@ class SlideImage:
152
166
 
153
167
  def read_region(
154
168
  self,
155
- location: np.ndarray | tuple[GenericNumber, GenericNumber],
169
+ location: GenericNumberArray | tuple[GenericNumber, GenericNumber],
156
170
  scaling: float,
157
- size: np.ndarray | tuple[int, int],
171
+ size: npt.NDArray[np.int_] | tuple[int, int],
158
172
  ) -> PIL.Image.Image:
159
173
  """Return a region at a specific scaling level of the pyramid.
160
174
 
@@ -202,8 +216,8 @@ class SlideImage:
202
216
  Examples
203
217
  --------
204
218
  The locations are defined at the requested scaling (with respect to level 0), so if we want to extract at
205
- location ``(location_x, location_y)`` of a scaling 0.5 (with respect to level 0), and have resulting tile size of
206
- ``(tile_size, tile_size)`` with a scaling factor of 0.5, we can use:
219
+ location ``(location_x, location_y)`` of a scaling 0.5 (with respect to level 0), and have
220
+ resulting tile size of ``(tile_size, tile_size)`` with a scaling factor of 0.5, we can use:
207
221
  >>> wsi.read_region(location=(coordinate_x, coordinate_y), scaling=0.5, size=(tile_size, tile_size))
208
222
  """
209
223
  owsi = self._wsi
@@ -247,7 +261,11 @@ class SlideImage:
247
261
  native_size_adapted = np.ceil(native_size_adapted).astype(int)
248
262
 
249
263
  # We extract the region via openslide with the required extra border
250
- region = owsi.read_region(tuple(level_zero_location_adapted), native_level, tuple(native_size_adapted))
264
+ region = owsi.read_region(
265
+ (level_zero_location_adapted[0], level_zero_location_adapted[1]),
266
+ native_level,
267
+ (native_size_adapted[0], native_size_adapted[1]),
268
+ )
251
269
 
252
270
  # Within this region, there are a bunch of extra pixels, we interpolate to sample
253
271
  # the pixel in the right position to retain the right sample weight.
@@ -256,7 +274,11 @@ class SlideImage:
256
274
  # TODO: This clipping could be in an error in OpenSlide mirax reader, but it's a minor thing for now
257
275
  box = (
258
276
  *fractional_coordinates,
259
- *np.clip((fractional_coordinates + native_size), a_min=0, a_max=np.asarray(region.size)),
277
+ *np.clip(
278
+ (fractional_coordinates + native_size),
279
+ a_min=0,
280
+ a_max=np.asarray(region.size),
281
+ ),
260
282
  )
261
283
  box = cast(tuple[float, float, float, float], box)
262
284
  size = cast(tuple[int, int], size)
@@ -307,7 +329,7 @@ class SlideImage:
307
329
  return self._identifier
308
330
 
309
331
  @property
310
- def properties(self) -> dict:
332
+ def properties(self) -> dict[str, str | int | float | bool] | None:
311
333
  """Returns any extra associated properties with the image."""
312
334
  return self._wsi.properties
313
335
 
@@ -338,7 +360,7 @@ class SlideImage:
338
360
  return width / height
339
361
 
340
362
  @property
341
- def slide_bounds(self):
363
+ def slide_bounds(self) -> tuple[tuple[int, int], tuple[int, int]]:
342
364
  """Returns the bounds of the slide. These can be smaller than the image itself.
343
365
  These bounds are in the format (x, y), (width, height), and are defined at level 0 of the image.
344
366
  """
@@ -1,13 +1,12 @@
1
- # coding=utf-8
1
+ # Copyright (c) dlup contributors
2
2
  """Defines the RegionView interface."""
3
3
  from __future__ import annotations
4
4
 
5
5
  from abc import ABC, abstractmethod
6
6
  from enum import Enum
7
- from typing import Iterable, Union, cast
7
+ from typing import cast
8
8
 
9
9
  import numpy as np
10
- import numpy.typing as npt
11
10
  import PIL.Image
12
11
 
13
12
  from dlup.types import GenericFloatArray, GenericIntArray