Skip to content

Commit

Permalink
Merge pull request #7712 from radarhere/type_hints_imageshow
Browse files Browse the repository at this point in the history
  • Loading branch information
hugovk authored Jan 14, 2024
2 parents 9923531 + c97b5c6 commit 1d25a39
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 28 deletions.
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ exclude = [
'^src/PIL/FpxImagePlugin.py$',
'^src/PIL/Image.py$',
'^src/PIL/ImageQt.py$',
'^src/PIL/ImageShow.py$',
'^src/PIL/ImImagePlugin.py$',
'^src/PIL/MicImagePlugin.py$',
'^src/PIL/PdfParser.py$',
Expand Down
6 changes: 4 additions & 2 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def _conv_type_shape(im):
_MAPMODES = ("L", "P", "RGBX", "RGBA", "CMYK", "I;16", "I;16L", "I;16B")


def getmodebase(mode):
def getmodebase(mode: str) -> str:
"""
Gets the "base" mode for given mode. This function returns "L" for
images that contain grayscale data, and "RGB" for images that
Expand Down Expand Up @@ -583,7 +583,9 @@ def _ensure_mutable(self):
else:
self.load()

def _dump(self, file=None, format=None, **options):
def _dump(
self, file: str | None = None, format: str | None = None, **options
) -> str:
suffix = ""
if format:
suffix = "." + format
Expand Down
60 changes: 35 additions & 25 deletions src/PIL/ImageShow.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@
#
from __future__ import annotations

import abc
import os
import shutil
import subprocess
import sys
from shlex import quote
from typing import Any

from . import Image

_viewers = []


def register(viewer, order=1):
def register(viewer, order: int = 1) -> None:
"""
The :py:func:`register` function is used to register additional viewers::
Expand All @@ -49,7 +51,7 @@ def register(viewer, order=1):
_viewers.insert(0, viewer)


def show(image, title=None, **options):
def show(image: Image.Image, title: str | None = None, **options: Any) -> bool:
r"""
Display a given image.
Expand All @@ -69,7 +71,7 @@ class Viewer:

# main api

def show(self, image, **options):
def show(self, image: Image.Image, **options: Any) -> int:
"""
The main function for displaying an image.
Converts the given image to the target format and displays it.
Expand All @@ -87,32 +89,32 @@ def show(self, image, **options):

# hook methods

format = None
format: str | None = None
"""The format to convert the image into."""
options = {}
options: dict[str, Any] = {}
"""Additional options used to convert the image."""

def get_format(self, image):
def get_format(self, image: Image.Image) -> str | None:
"""Return format name, or ``None`` to save as PGM/PPM."""
return self.format

def get_command(self, file, **options):
def get_command(self, file: str, **options: Any) -> str:
"""
Returns the command used to display the file.
Not implemented in the base class.
"""
msg = "unavailable in base viewer"
raise NotImplementedError(msg)

def save_image(self, image):
def save_image(self, image: Image.Image) -> str:
"""Save to temporary file and return filename."""
return image._dump(format=self.get_format(image), **self.options)

def show_image(self, image, **options):
def show_image(self, image: Image.Image, **options: Any) -> int:
"""Display the given image."""
return self.show_file(self.save_image(image), **options)

def show_file(self, path, **options):
def show_file(self, path: str, **options: Any) -> int:
"""
Display given file.
"""
Expand All @@ -129,7 +131,7 @@ class WindowsViewer(Viewer):
format = "PNG"
options = {"compress_level": 1, "save_all": True}

def get_command(self, file, **options):
def get_command(self, file: str, **options: Any) -> str:
return (
f'start "Pillow" /WAIT "{file}" '
"&& ping -n 4 127.0.0.1 >NUL "
Expand All @@ -147,14 +149,14 @@ class MacViewer(Viewer):
format = "PNG"
options = {"compress_level": 1, "save_all": True}

def get_command(self, file, **options):
def get_command(self, file: str, **options: Any) -> str:
# on darwin open returns immediately resulting in the temp
# file removal while app is opening
command = "open -a Preview.app"
command = f"({command} {quote(file)}; sleep 20; rm -f {quote(file)})&"
return command

def show_file(self, path, **options):
def show_file(self, path: str, **options: Any) -> int:
"""
Display given file.
"""
Expand All @@ -180,7 +182,11 @@ class UnixViewer(Viewer):
format = "PNG"
options = {"compress_level": 1, "save_all": True}

def get_command(self, file, **options):
@abc.abstractmethod
def get_command_ex(self, file: str, **options: Any) -> tuple[str, str]:
pass # pragma: no cover

def get_command(self, file: str, **options: Any) -> str:
command = self.get_command_ex(file, **options)[0]
return f"({command} {quote(file)}"

Expand All @@ -190,11 +196,11 @@ class XDGViewer(UnixViewer):
The freedesktop.org ``xdg-open`` command.
"""

def get_command_ex(self, file, **options):
def get_command_ex(self, file: str, **options: Any) -> tuple[str, str]:
command = executable = "xdg-open"
return command, executable

def show_file(self, path, **options):
def show_file(self, path: str, **options: Any) -> int:
"""
Display given file.
"""
Expand All @@ -208,13 +214,15 @@ class DisplayViewer(UnixViewer):
This viewer supports the ``title`` parameter.
"""

def get_command_ex(self, file, title=None, **options):
def get_command_ex(
self, file: str, title: str | None = None, **options: Any
) -> tuple[str, str]:
command = executable = "display"
if title:
command += f" -title {quote(title)}"
return command, executable

def show_file(self, path, **options):
def show_file(self, path: str, **options: Any) -> int:
"""
Display given file.
"""
Expand All @@ -231,12 +239,12 @@ def show_file(self, path, **options):
class GmDisplayViewer(UnixViewer):
"""The GraphicsMagick ``gm display`` command."""

def get_command_ex(self, file, **options):
def get_command_ex(self, file: str, **options: Any) -> tuple[str, str]:
executable = "gm"
command = "gm display"
return command, executable

def show_file(self, path, **options):
def show_file(self, path: str, **options: Any) -> int:
"""
Display given file.
"""
Expand All @@ -247,12 +255,12 @@ def show_file(self, path, **options):
class EogViewer(UnixViewer):
"""The GNOME Image Viewer ``eog`` command."""

def get_command_ex(self, file, **options):
def get_command_ex(self, file: str, **options: Any) -> tuple[str, str]:
executable = "eog"
command = "eog -n"
return command, executable

def show_file(self, path, **options):
def show_file(self, path: str, **options: Any) -> int:
"""
Display given file.
"""
Expand All @@ -266,15 +274,17 @@ class XVViewer(UnixViewer):
This viewer supports the ``title`` parameter.
"""

def get_command_ex(self, file, title=None, **options):
def get_command_ex(
self, file: str, title: str | None = None, **options: Any
) -> tuple[str, str]:
# note: xv is pretty outdated. most modern systems have
# imagemagick's display command instead.
command = executable = "xv"
if title:
command += f" -name {quote(title)}"
return command, executable

def show_file(self, path, **options):
def show_file(self, path: str, **options: Any) -> int:
"""
Display given file.
"""
Expand Down Expand Up @@ -304,7 +314,7 @@ def show_file(self, path, **options):
class IPythonViewer(Viewer):
"""The viewer for IPython frontends."""

def show_image(self, image, **options):
def show_image(self, image: Image.Image, **options: Any) -> int:
ipython_display(image)
return 1

Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ commands =
[testenv:mypy]
skip_install = true
deps =
ipython
mypy==1.7.1
numpy
extras =
Expand Down

0 comments on commit 1d25a39

Please sign in to comment.