Skip to content

Commit

Permalink
Merge pull request #7790 from radarhere/pyproject
Browse files Browse the repository at this point in the history
Removed mypy excludes, except for olefile-related files
  • Loading branch information
radarhere authored Feb 11, 2024
2 parents 6782a07 + 112a5a4 commit 5d6f22d
Show file tree
Hide file tree
Showing 15 changed files with 174 additions and 102 deletions.
2 changes: 2 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ exclude_also =
if DEBUG:
# Don't complain about compatibility code for missing optional dependencies
except ImportError
if TYPE_CHECKING:
@abc.abstractmethod

[run]
omit =
Expand Down
10 changes: 0 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,6 @@ warn_redundant_casts = true
warn_unreachable = true
warn_unused_ignores = true
exclude = [
'^src/PIL/_tkinter_finder.py$',
'^src/PIL/DdsImagePlugin.py$',
'^src/PIL/FpxImagePlugin.py$',
'^src/PIL/Image.py$',
'^src/PIL/ImageQt.py$',
'^src/PIL/ImImagePlugin.py$',
'^src/PIL/MicImagePlugin.py$',
'^src/PIL/PdfParser.py$',
'^src/PIL/PyAccess.py$',
'^src/PIL/TiffImagePlugin.py$',
'^src/PIL/TiffTags.py$',
'^src/PIL/WebPImagePlugin.py$',
]
16 changes: 10 additions & 6 deletions src/PIL/DdsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,13 +270,17 @@ class D3DFMT(IntEnum):
# Backward compatibility layer
module = sys.modules[__name__]
for item in DDSD:
assert item.name is not None
setattr(module, "DDSD_" + item.name, item.value)
for item in DDSCAPS:
setattr(module, "DDSCAPS_" + item.name, item.value)
for item in DDSCAPS2:
setattr(module, "DDSCAPS2_" + item.name, item.value)
for item in DDPF:
setattr(module, "DDPF_" + item.name, item.value)
for item1 in DDSCAPS:
assert item1.name is not None
setattr(module, "DDSCAPS_" + item1.name, item1.value)
for item2 in DDSCAPS2:
assert item2.name is not None
setattr(module, "DDSCAPS2_" + item2.name, item2.value)
for item3 in DDPF:
assert item3.name is not None
setattr(module, "DDPF_" + item3.name, item3.value)

DDS_FOURCC = DDPF.FOURCC
DDS_RGB = DDPF.RGB
Expand Down
4 changes: 2 additions & 2 deletions src/PIL/ImImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@
for i in ["32S"]:
OPEN[f"L {i} image"] = ("I", f"I;{i}")
OPEN[f"L*{i} image"] = ("I", f"I;{i}")
for i in range(2, 33):
OPEN[f"L*{i} image"] = ("F", f"F;{i}")
for j in range(2, 33):
OPEN[f"L*{j} image"] = ("F", f"F;{j}")


# --------------------------------------------------------------------
Expand Down
87 changes: 57 additions & 30 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from __future__ import annotations

import abc
import atexit
import builtins
import io
Expand All @@ -40,11 +41,8 @@
from collections.abc import Callable, MutableMapping
from enum import IntEnum
from pathlib import Path

try:
from defusedxml import ElementTree
except ImportError:
ElementTree = None
from types import ModuleType
from typing import IO, TYPE_CHECKING, Any

# VERSION was removed in Pillow 6.0.0.
# PILLOW_VERSION was removed in Pillow 9.0.0.
Expand All @@ -60,6 +58,12 @@
from ._binary import i32le, o32be, o32le
from ._util import DeferredError, is_path

ElementTree: ModuleType | None
try:
from defusedxml import ElementTree
except ImportError:
ElementTree = None

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -110,6 +114,7 @@ class DecompressionBombError(Exception):


USE_CFFI_ACCESS = False
cffi: ModuleType | None
try:
import cffi
except ImportError:
Expand Down Expand Up @@ -211,14 +216,22 @@ class Quantize(IntEnum):
# --------------------------------------------------------------------
# Registries

ID = []
OPEN = {}
MIME = {}
SAVE = {}
SAVE_ALL = {}
EXTENSION = {}
DECODERS = {}
ENCODERS = {}
if TYPE_CHECKING:
from . import ImageFile
ID: list[str] = []
OPEN: dict[
str,
tuple[
Callable[[IO[bytes], str | bytes], ImageFile.ImageFile],
Callable[[bytes], bool] | None,
],
] = {}
MIME: dict[str, str] = {}
SAVE: dict[str, Callable[[Image, IO[bytes], str | bytes], None]] = {}
SAVE_ALL: dict[str, Callable[[Image, IO[bytes], str | bytes], None]] = {}
EXTENSION: dict[str, str] = {}
DECODERS: dict[str, object] = {}
ENCODERS: dict[str, object] = {}

# --------------------------------------------------------------------
# Modes
Expand Down Expand Up @@ -2383,12 +2396,12 @@ def save(self, fp, format=None, **params) -> None:
may have been created, and may contain partial data.
"""

filename = ""
filename: str | bytes = ""
open_fp = False
if isinstance(fp, Path):
filename = str(fp)
open_fp = True
elif is_path(fp):
elif isinstance(fp, (str, bytes)):
filename = fp
open_fp = True
elif fp == sys.stdout:
Expand All @@ -2398,7 +2411,7 @@ def save(self, fp, format=None, **params) -> None:
pass
if not filename and hasattr(fp, "name") and is_path(fp.name):
# only set the name for metadata purposes
filename = fp.name
filename = os.path.realpath(os.fspath(fp.name))

# may mutate self!
self._ensure_mutable()
Expand All @@ -2409,7 +2422,8 @@ def save(self, fp, format=None, **params) -> None:

preinit()

ext = os.path.splitext(filename)[1].lower()
filename_ext = os.path.splitext(filename)[1].lower()
ext = filename_ext.decode() if isinstance(filename_ext, bytes) else filename_ext

if not format:
if ext not in EXTENSION:
Expand Down Expand Up @@ -2451,7 +2465,7 @@ def save(self, fp, format=None, **params) -> None:
if open_fp:
fp.close()

def seek(self, frame) -> Image:
def seek(self, frame) -> None:
"""
Seeks to the given frame in this sequence file. If you seek
beyond the end of the sequence, the method raises an
Expand Down Expand Up @@ -2511,10 +2525,8 @@ def split(self) -> tuple[Image, ...]:

self.load()
if self.im.bands == 1:
ims = [self.copy()]
else:
ims = map(self._new, self.im.split())
return tuple(ims)
return (self.copy(),)
return tuple(map(self._new, self.im.split()))

def getchannel(self, channel):
"""
Expand Down Expand Up @@ -2871,7 +2883,14 @@ class ImageTransformHandler:
(for use with :py:meth:`~PIL.Image.Image.transform`)
"""

pass
@abc.abstractmethod
def transform(
self,
size: tuple[int, int],
image: Image,
**options: dict[str, str | int | tuple[int, ...] | list[int]],
) -> Image:
pass


# --------------------------------------------------------------------
Expand Down Expand Up @@ -3243,11 +3262,9 @@ def open(fp, mode="r", formats=None) -> Image:
raise TypeError(msg)

exclusive_fp = False
filename = ""
if isinstance(fp, Path):
filename = str(fp.resolve())
elif is_path(fp):
filename = fp
filename: str | bytes = ""
if is_path(fp):
filename = os.path.realpath(os.fspath(fp))

if filename:
fp = builtins.open(filename, "rb")
Expand Down Expand Up @@ -3421,7 +3438,11 @@ def merge(mode, bands):
# Plugin registry


def register_open(id, factory, accept=None) -> None:
def register_open(
id,
factory: Callable[[IO[bytes], str | bytes], ImageFile.ImageFile],
accept: Callable[[bytes], bool] | None = None,
) -> None:
"""
Register an image file plugin. This function should not be used
in application code.
Expand Down Expand Up @@ -3631,7 +3652,13 @@ def _apply_env_variables(env=None):
atexit.register(core.clear_cache)


class Exif(MutableMapping):
if TYPE_CHECKING:
_ExifBase = MutableMapping[int, Any]
else:
_ExifBase = MutableMapping


class Exif(_ExifBase):
"""
This class provides read and write access to EXIF image data::
Expand Down
12 changes: 10 additions & 2 deletions src/PIL/ImageQt.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,26 @@

import sys
from io import BytesIO
from typing import Callable

from . import Image
from ._util import is_path

qt_version: str | None
qt_versions = [
["6", "PyQt6"],
["side6", "PySide6"],
]

# If a version has already been imported, attempt it first
qt_versions.sort(key=lambda qt_version: qt_version[1] in sys.modules, reverse=True)
for qt_version, qt_module in qt_versions:
qt_versions.sort(key=lambda version: version[1] in sys.modules, reverse=True)
for version, qt_module in qt_versions:
try:
QBuffer: type
QIODevice: type
QImage: type
QPixmap: type
qRgba: Callable[[int, int, int, int], int]
if qt_module == "PyQt6":
from PyQt6.QtCore import QBuffer, QIODevice
from PyQt6.QtGui import QImage, QPixmap, qRgba
Expand All @@ -41,6 +48,7 @@
except (ImportError, RuntimeError):
continue
qt_is_installed = True
qt_version = version
break
else:
qt_is_installed = False
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/ImageShow.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ class UnixViewer(Viewer):

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

def get_command(self, file: str, **options: Any) -> str:
command = self.get_command_ex(file, **options)[0]
Expand Down
11 changes: 9 additions & 2 deletions src/PIL/PdfParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import re
import time
import zlib
from typing import TYPE_CHECKING, Any, List, Union


# see 7.9.2.2 Text String Type on page 86 and D.3 PDFDocEncoding Character Set
Expand Down Expand Up @@ -239,12 +240,18 @@ def __bytes__(self):
return bytes(result)


class PdfArray(list):
class PdfArray(List[Any]):
def __bytes__(self):
return b"[ " + b" ".join(pdf_repr(x) for x in self) + b" ]"


class PdfDict(collections.UserDict):
if TYPE_CHECKING:
_DictBase = collections.UserDict[Union[str, bytes], Any]
else:
_DictBase = collections.UserDict


class PdfDict(_DictBase):
def __setattr__(self, key, value):
if key == "data":
collections.UserDict.__setattr__(self, key, value)
Expand Down
1 change: 1 addition & 0 deletions src/PIL/PyAccess.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

from ._deprecate import deprecate

FFI: type
try:
from cffi import FFI

Expand Down
Loading

0 comments on commit 5d6f22d

Please sign in to comment.