Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 11 additions & 16 deletions examples/deepzoom/deepzoom_multiserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,12 @@
import os
from pathlib import Path, PurePath
from threading import Lock
from typing import TYPE_CHECKING, Any, Literal
from typing import Any, Literal, TypeAlias
import zlib

from flask import Flask, Response, abort, make_response, render_template, url_for
from PIL import Image, ImageCms

if TYPE_CHECKING:
# Python 3.10+
from typing import TypeAlias

if os.name == 'nt':
_dll_path = os.getenv('OPENSLIDE_PATH')
if _dll_path is not None:
Expand Down Expand Up @@ -68,17 +64,16 @@
)
SRGB_PROFILE = ImageCms.getOpenProfile(BytesIO(SRGB_PROFILE_BYTES))

if TYPE_CHECKING:
ColorMode: TypeAlias = Literal[
'default',
'absolute-colorimetric',
'perceptual',
'relative-colorimetric',
'saturation',
'embed',
'ignore',
]
Transform: TypeAlias = Callable[[Image.Image], None]
ColorMode: TypeAlias = Literal[
'default',
'absolute-colorimetric',
'perceptual',
'relative-colorimetric',
'saturation',
'embed',
'ignore',
]
Transform: TypeAlias = Callable[[Image.Image], None]


class DeepZoomMultiServer(Flask):
Expand Down
27 changes: 11 additions & 16 deletions examples/deepzoom/deepzoom_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,13 @@
import os
from pathlib import Path
import re
from typing import TYPE_CHECKING, Any, Literal
from typing import Any, Literal, TypeAlias
from unicodedata import normalize
import zlib

from flask import Flask, Response, abort, make_response, render_template, url_for
from PIL import Image, ImageCms

if TYPE_CHECKING:
# Python 3.10+
from typing import TypeAlias

if os.name == 'nt':
_dll_path = os.getenv('OPENSLIDE_PATH')
if _dll_path is not None:
Expand Down Expand Up @@ -70,17 +66,16 @@
)
SRGB_PROFILE = ImageCms.getOpenProfile(BytesIO(SRGB_PROFILE_BYTES))

if TYPE_CHECKING:
ColorMode: TypeAlias = Literal[
'default',
'absolute-colorimetric',
'perceptual',
'relative-colorimetric',
'saturation',
'embed',
'ignore',
]
Transform: TypeAlias = Callable[[Image.Image], None]
ColorMode: TypeAlias = Literal[
'default',
'absolute-colorimetric',
'perceptual',
'relative-colorimetric',
'saturation',
'embed',
'ignore',
]
Transform: TypeAlias = Callable[[Image.Image], None]


class DeepZoomServer(Flask):
Expand Down
27 changes: 12 additions & 15 deletions examples/deepzoom/deepzoom_tile.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,12 @@
import re
import shutil
import sys
from typing import TYPE_CHECKING, Literal
from typing import TYPE_CHECKING, Literal, TypeAlias
from unicodedata import normalize
import zlib

from PIL import Image, ImageCms

if TYPE_CHECKING:
# Python 3.10+
from typing import TypeAlias

if os.name == 'nt':
_dll_path = os.getenv('OPENSLIDE_PATH')
if _dll_path is not None:
Expand Down Expand Up @@ -76,20 +72,21 @@
)
SRGB_PROFILE = ImageCms.getOpenProfile(BytesIO(SRGB_PROFILE_BYTES))

ColorMode: TypeAlias = Literal[
'default',
'absolute-colorimetric',
'perceptual',
'relative-colorimetric',
'saturation',
'embed',
'ignore',
]
Transform: TypeAlias = Callable[[Image.Image], None]
if TYPE_CHECKING:
ColorMode: TypeAlias = Literal[
'default',
'absolute-colorimetric',
'perceptual',
'relative-colorimetric',
'saturation',
'embed',
'ignore',
]
# Python 3.12+
TileQueue: TypeAlias = multiprocessing.queues.JoinableQueue[
tuple[str | None, int, tuple[int, int], Path] | None
]
Transform: TypeAlias = Callable[[Image.Image], None]


class TileWorker(Process):
Expand Down
6 changes: 1 addition & 5 deletions openslide/deepzoom.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,13 @@

from io import BytesIO
import math
from typing import TYPE_CHECKING
from typing import TypeGuard
from xml.etree.ElementTree import Element, ElementTree, SubElement

from PIL import Image

import openslide

if TYPE_CHECKING:
# Python 3.10+
from typing import TypeGuard


class DeepZoomGenerator:
"""Generates Deep Zoom tiles and metadata."""
Expand Down
44 changes: 18 additions & 26 deletions openslide/lowlevel.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,13 @@
from itertools import count
import os
import platform
from typing import TYPE_CHECKING, Any, Protocol, TypeVar, cast
from typing import TYPE_CHECKING, Any, ParamSpec, Protocol, TypeAlias, TypeVar, cast

from PIL import Image

from . import _convert

if TYPE_CHECKING:
# Python 3.10+
from typing import ParamSpec, TypeAlias

from _convert import _Buffer


Expand Down Expand Up @@ -199,9 +196,7 @@ def from_param(cls, obj: _OpenSlideCache) -> _OpenSlideCache:
return obj


if TYPE_CHECKING:
# Python 3.10+
Filename: TypeAlias = str | bytes | os.PathLike[Any]
Filename: TypeAlias = str | bytes | os.PathLike[Any]


class _filename_p:
Expand Down Expand Up @@ -314,24 +309,25 @@ def __call__(self, *_args: Any) -> Any:
raise OpenSlideVersionError(self._minimum_version)


# gate runtime code that requires ParamSpec, Python 3.10+
if TYPE_CHECKING:
_P = ParamSpec('_P')
_T = TypeVar('_T', covariant=True)
_P = ParamSpec('_P')
_T = TypeVar('_T', covariant=True)

class _Func(Protocol[_P, _T]):
available: bool

def __call__(self, *args: _P.args) -> _T: ... # type: ignore[valid-type]
class _Func(Protocol[_P, _T]):
available: bool

class _CTypesFunc(_Func[_P, _T]):
restype: type | None
argtypes: list[type]
errcheck: _ErrCheck
def __call__(self, *args: _P.args) -> _T: ... # type: ignore[valid-type]

_ErrCheck: TypeAlias = (
Callable[[Any, _CTypesFunc[..., Any], tuple[Any, ...]], Any] | None
)

class _CTypesFunc(_Func[_P, _T]):
restype: type | None
argtypes: list[type]
errcheck: _ErrCheck


_ErrCheck: TypeAlias = (
Callable[[Any, _CTypesFunc[..., Any], tuple[Any, ...]], Any] | None
)


# resolve and return an OpenSlide function with the specified properties
Expand Down Expand Up @@ -361,11 +357,7 @@ def _wraps_funcs(
wrapped: list[_Func[..., Any]],
) -> Callable[[Callable[_P, _T]], _Func[_P, _T]]:
def decorator(fn: Callable[_P, _T]) -> _Func[_P, _T]:
if TYPE_CHECKING:
# requires ParamSpec, Python 3.10+
f = cast(_Func[_P, _T], fn)
else:
f = fn
f = cast('_Func[_P, _T]', fn)
f.available = True
for w in wrapped:
f.available = f.available and w.available
Expand Down