-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Added type hints for PixelAccess related methods and others #8032
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 18 commits
5f805c3
b60b606
a304fd5
74b87ae
c2cb944
007caae
b2ce2f6
6affb12
c1f10c1
7e14364
eb56f3e
31a8da4
2a2033e
2381103
0a2baab
20ce7ad
32264a1
b64847e
ded4045
d0d53d4
ab18395
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,7 +41,16 @@ | |
| from collections.abc import Callable, MutableMapping | ||
| from enum import IntEnum | ||
| from types import ModuleType | ||
| from typing import IO, TYPE_CHECKING, Any, Literal, Protocol, Sequence, Tuple, cast | ||
| from typing import ( | ||
| IO, | ||
| TYPE_CHECKING, | ||
| Any, | ||
| Literal, | ||
| Protocol, | ||
| Sequence, | ||
| Tuple, | ||
| cast, | ||
| ) | ||
|
|
||
| # VERSION was removed in Pillow 6.0.0. | ||
| # PILLOW_VERSION was removed in Pillow 9.0.0. | ||
|
|
@@ -218,7 +227,7 @@ class Quantize(IntEnum): | |
| # Registries | ||
|
|
||
| if TYPE_CHECKING: | ||
| from . import ImageFile | ||
| from . import ImageFile, PyAccess | ||
| ID: list[str] = [] | ||
| OPEN: dict[ | ||
| str, | ||
|
|
@@ -863,7 +872,7 @@ def frombytes(self, data: bytes, decoder_name: str = "raw", *args) -> None: | |
| msg = "cannot decode image data" | ||
| raise ValueError(msg) | ||
|
|
||
| def load(self): | ||
| def load(self) -> core.PixelAccess | PyAccess.PyAccess | None: | ||
| """ | ||
| Allocates storage for the image and loads the pixel data. In | ||
| normal cases, you don't need to call this method, since the | ||
|
|
@@ -876,7 +885,7 @@ def load(self): | |
| operations. See :ref:`file-handling` for more information. | ||
|
|
||
| :returns: An image access object. | ||
| :rtype: :ref:`PixelAccess` or :py:class:`PIL.PyAccess` | ||
| :rtype: :py:class:`.PixelAccess` or :py:class:`.PyAccess` | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My initial reaction to this was to feel confused , because the return type is PixelAccess or None, but this says PixelAccess or PyAccess. Of course, the return type uses PixelAccess the protocol, not the class. But should the protocol have a different name perhaps to avoid confusion?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Be aware that this will become simpler after Pillow 10.4.0, as PyAccess will end deprecation and be removed.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that after 10.4.0, we'll have no need for the protocol - we can just use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough, I've pushed a similar commit, see comment in nulano#39. |
||
| """ | ||
| if self.im is not None and self.palette and self.palette.dirty: | ||
| # realize palette | ||
|
|
@@ -905,6 +914,7 @@ def load(self): | |
| if self.pyaccess: | ||
| return self.pyaccess | ||
| return self.im.pixel_access(self.readonly) | ||
| return None | ||
|
|
||
| def verify(self) -> None: | ||
| """ | ||
|
|
@@ -1092,7 +1102,10 @@ def convert_transparency(m, v): | |
| del new_im.info["transparency"] | ||
| if trns is not None: | ||
| try: | ||
| new_im.info["transparency"] = new_im.palette.getcolor(trns, new_im) | ||
| new_im.info["transparency"] = new_im.palette.getcolor( | ||
| cast(Tuple[int, int, int], trns), # trns was converted to RGB | ||
| new_im, | ||
| ) | ||
| except Exception: | ||
| # if we can't make a transparent color, don't leave the old | ||
| # transparency hanging around to mess us up. | ||
|
|
@@ -1142,7 +1155,10 @@ def convert_transparency(m, v): | |
| if trns is not None: | ||
| if new_im.mode == "P": | ||
| try: | ||
| new_im.info["transparency"] = new_im.palette.getcolor(trns, new_im) | ||
| new_im.info["transparency"] = new_im.palette.getcolor( | ||
| cast(Tuple[int, int, int], trns), # trns was converted to RGB | ||
| new_im, | ||
| ) | ||
| except ValueError as e: | ||
| del new_im.info["transparency"] | ||
| if str(e) != "cannot allocate more than 256 colors": | ||
|
|
@@ -1633,7 +1649,9 @@ def apply_transparency(self) -> None: | |
|
|
||
| del self.info["transparency"] | ||
|
|
||
| def getpixel(self, xy): | ||
| def getpixel( | ||
| self, xy: tuple[int, int] | list[int] | ||
| ) -> float | tuple[int, ...] | None: | ||
| """ | ||
| Returns the pixel value at a given position. | ||
|
|
||
|
|
@@ -1902,15 +1920,14 @@ def point(self, data): | |
| lut = [round(i) for i in lut] | ||
| return self._new(self.im.point(lut, mode)) | ||
|
|
||
| def putalpha(self, alpha): | ||
| def putalpha(self, alpha: Image | int) -> None: | ||
| """ | ||
| Adds or replaces the alpha layer in this image. If the image | ||
| does not have an alpha layer, it's converted to "LA" or "RGBA". | ||
| The new layer must be either "L" or "1". | ||
|
|
||
| :param alpha: The new alpha layer. This can either be an "L" or "1" | ||
| image having the same size as this image, or an integer or | ||
| other color value. | ||
| image having the same size as this image, or an integer. | ||
| """ | ||
|
|
||
| self._ensure_mutable() | ||
|
|
@@ -1949,6 +1966,7 @@ def putalpha(self, alpha): | |
| alpha = alpha.convert("L") | ||
| else: | ||
| # constant alpha | ||
| alpha = cast(int, alpha) # see python/typing#1013 | ||
| try: | ||
| self.im.fillband(band, alpha) | ||
| except (AttributeError, ValueError): | ||
|
|
@@ -2014,7 +2032,9 @@ def putpalette(self, data, rawmode="RGB") -> None: | |
| self.palette.mode = "RGB" | ||
| self.load() # install new palette | ||
|
|
||
| def putpixel(self, xy, value): | ||
| def putpixel( | ||
| self, xy: tuple[int, int], value: float | tuple[int, ...] | list[int] | ||
| ) -> None: | ||
| """ | ||
| Modifies the pixel at the given position. The color is given as | ||
| a single numerical value for single-band images, and a tuple for | ||
|
|
@@ -2052,9 +2072,8 @@ def putpixel(self, xy, value): | |
| if self.mode == "PA": | ||
| alpha = value[3] if len(value) == 4 else 255 | ||
| value = value[:3] | ||
| value = self.palette.getcolor(value, self) | ||
| if self.mode == "PA": | ||
| value = (value, alpha) | ||
| palette_index = self.palette.getcolor(value, self) | ||
| value = (palette_index, alpha) if self.mode == "PA" else palette_index | ||
| return self.im.putpixel(xy, value) | ||
|
|
||
| def remap_palette(self, dest_map, source_palette=None): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,11 +22,18 @@ | |
| import subprocess | ||
| import sys | ||
| import tempfile | ||
| from typing import Union, cast | ||
|
|
||
| from . import Image | ||
|
|
||
|
|
||
| def grab(bbox=None, include_layered_windows=False, all_screens=False, xdisplay=None): | ||
| def grab( | ||
| bbox: tuple[int, int, int, int] | None = None, | ||
| include_layered_windows: bool = False, | ||
| all_screens: bool = False, | ||
| xdisplay: str | None = None, | ||
| ) -> Image.Image: | ||
| im: Image.Image | ||
| if xdisplay is None: | ||
| if sys.platform == "darwin": | ||
| fh, filepath = tempfile.mkstemp(".png") | ||
|
|
@@ -63,6 +70,7 @@ def grab(bbox=None, include_layered_windows=False, all_screens=False, xdisplay=N | |
| left, top, right, bottom = bbox | ||
| im = im.crop((left - x0, top - y0, right - x0, bottom - y0)) | ||
| return im | ||
| xdisplay = cast(Union[str, None], xdisplay) # type: ignore[redundant-cast, unused-ignore] | ||
|
||
| try: | ||
| if not Image.core.HAVE_XCB: | ||
| msg = "Pillow was built without XCB support" | ||
|
|
@@ -94,7 +102,7 @@ def grab(bbox=None, include_layered_windows=False, all_screens=False, xdisplay=N | |
| return im | ||
|
|
||
|
|
||
| def grabclipboard(): | ||
| def grabclipboard() -> Image.Image | list[str] | None: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not opposed to changing this to
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I hope that we can change return types without deprecation, but I can appreciate that we could be a bit forwards-compatible here. There's also no reason for the user to expect |
||
| if sys.platform == "darwin": | ||
| fh, filepath = tempfile.mkstemp(".png") | ||
| os.close(fh) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.