@@ -205,6 +205,90 @@ def is_ngff( # noqa: PLR0911
205205 return is_zarr (path )
206206
207207
208+ def _handle_virtual_wsi (
209+ last_suffix : str ,
210+ input_path : Path ,
211+ mpp : tuple [Number , Number ] | None ,
212+ power : Number | None ,
213+ ) -> VirtualWSIReader | None :
214+ """Handle virtual WSI cases.
215+
216+ Args:
217+ last_suffix (str):
218+ Suffix of the file to read.
219+ input_path (Path):
220+ Input path to virtual WSI.
221+ mpp (:obj:`tuple` or :obj:`list` or :obj:`None`, optional):
222+ The MPP of the WSI. If not provided, the MPP is approximated
223+ from the objective power.
224+ power (:obj:`float` or :obj:`None`, optional):
225+ The objective power of the WSI. If not provided, the power
226+ is approximated from the MPP.
227+
228+ Returns:
229+ VirtualWSIReader | None:
230+ :class:`VirtualWSIReader` if input_path is valid path to virtual WSI
231+ otherwise None.
232+
233+ """
234+
235+ # Handle homogeneous cases (based on final suffix)
236+ def np_virtual_wsi (
237+ input_path : np .ndarray ,
238+ * args : Number | tuple | str | WSIMeta | None ,
239+ ** kwargs : dict ,
240+ ) -> VirtualWSIReader :
241+ """Create a virtual WSI from a numpy array."""
242+ return VirtualWSIReader (input_path , * args , ** kwargs )
243+
244+ suffix_to_reader = {
245+ ".npy" : np_virtual_wsi ,
246+ ".jp2" : JP2WSIReader ,
247+ ".jpeg" : VirtualWSIReader ,
248+ ".jpg" : VirtualWSIReader ,
249+ ".png" : VirtualWSIReader ,
250+ ".tif" : VirtualWSIReader ,
251+ ".tiff" : VirtualWSIReader ,
252+ }
253+
254+ if last_suffix in suffix_to_reader :
255+ return suffix_to_reader [last_suffix ](input_path , mpp = mpp , power = power )
256+
257+ return None
258+
259+
260+ def _handle_tiff_wsi (
261+ input_path : Path , mpp : tuple [Number , Number ] | None , power : Number | None
262+ ) -> TIFFWSIReader | OpenSlideWSIReader | None :
263+ """Handle TIFF WSI cases.
264+
265+ Args:
266+ input_path (Path):
267+ Input path to virtual WSI.
268+ mpp (:obj:`tuple` or :obj:`list` or :obj:`None`, optional):
269+ The MPP of the WSI. If not provided, the MPP is approximated
270+ from the objective power.
271+ power (:obj:`float` or :obj:`None`, optional):
272+ The objective power of the WSI. If not provided, the power
273+ is approximated from the MPP.
274+
275+ Returns:
276+ OpenSlideWSIReader | TIFFWSIReader | None:
277+ :class:`OpenSlideWSIReader` or :class:`TIFFWSIReader` if input_path is
278+ valid path to tiff WSI otherwise None.
279+
280+ """
281+ if openslide .OpenSlide .detect_format (input_path ) is not None :
282+ try :
283+ return OpenSlideWSIReader (input_path , mpp = mpp , power = power )
284+ except openslide .OpenSlideError :
285+ pass
286+ if is_tiled_tiff (input_path ):
287+ return TIFFWSIReader (input_path , mpp = mpp , power = power )
288+
289+ return None
290+
291+
208292class WSIReader :
209293 """Base whole slide image (WSI) reader class.
210294
@@ -228,7 +312,7 @@ class WSIReader:
228312 """
229313
230314 @staticmethod
231- def open ( # noqa: PLR0911, PLR0912, C901
315+ def open ( # noqa: PLR0911
232316 input_img : str | Path | np .ndarray | WSIReader ,
233317 mpp : tuple [Number , Number ] | None = None ,
234318 power : Number | None = None ,
@@ -279,7 +363,6 @@ def open( # noqa: PLR0911, PLR0912, C901
279363 WSIReader .verify_supported_wsi (input_path )
280364
281365 # Handle special cases first (DICOM, Zarr/NGFF, OME-TIFF)
282-
283366 if is_dicom (input_path ):
284367 return DICOMWSIReader (input_path , mpp = mpp , power = power )
285368
@@ -301,35 +384,16 @@ def open( # noqa: PLR0911, PLR0912, C901
301384 return TIFFWSIReader (input_path , mpp = mpp , power = power )
302385
303386 if last_suffix in (".tif" , ".tiff" ):
304- if openslide .OpenSlide .detect_format (input_path ) is not None :
305- try :
306- return OpenSlideWSIReader (input_path , mpp = mpp , power = power )
307- except openslide .OpenSlideError :
308- pass
309- if is_tiled_tiff (input_path ):
310- return TIFFWSIReader (input_path , mpp = mpp , power = power )
311-
312- # Handle homogeneous cases (based on final suffix)
313- def np_virtual_wsi (
314- input_path : np .ndarray ,
315- * args : Number | tuple | str | WSIMeta | None ,
316- ** kwargs : dict ,
317- ) -> VirtualWSIReader :
318- """Create a virtual WSI from a numpy array."""
319- return VirtualWSIReader (input_path , * args , ** kwargs )
320-
321- suffix_to_reader = {
322- ".npy" : np_virtual_wsi ,
323- ".jp2" : JP2WSIReader ,
324- ".jpeg" : VirtualWSIReader ,
325- ".jpg" : VirtualWSIReader ,
326- ".png" : VirtualWSIReader ,
327- ".tif" : VirtualWSIReader ,
328- ".tiff" : VirtualWSIReader ,
329- }
387+ tiff_wsi = _handle_tiff_wsi (input_path , mpp = mpp , power = power )
388+ if tiff_wsi is not None :
389+ return tiff_wsi
390+
391+ virtual_wsi = _handle_virtual_wsi (
392+ last_suffix = last_suffix , input_path = input_path , mpp = mpp , power = power
393+ )
330394
331- if last_suffix in suffix_to_reader :
332- return suffix_to_reader [ last_suffix ]( input_path , mpp = mpp , power = power )
395+ if virtual_wsi is not None :
396+ return virtual_wsi
333397
334398 # Try openslide last
335399 return OpenSlideWSIReader (input_path , mpp = mpp , power = power )
0 commit comments