Skip to content

Commit 5a8e7dd

Browse files
committed
Added type hints
1 parent 9525553 commit 5a8e7dd

4 files changed

Lines changed: 40 additions & 39 deletions

File tree

Tests/test_imagedraw.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1519,7 +1519,7 @@ def test_compute_regular_polygon_vertices(
15191519
[
15201520
(None, (50, 50, 25), 0, TypeError, "n_sides should be an int"),
15211521
(1, (50, 50, 25), 0, ValueError, "n_sides should be an int > 2"),
1522-
(3, 50, 0, TypeError, "bounding_circle should be a tuple"),
1522+
(3, 50, 0, TypeError, "bounding_circle should be a sequence"),
15231523
(
15241524
3,
15251525
(50, 50, 100, 100),

src/PIL/Image.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ def close(self):
571571
# object is gone.
572572
self.im = DeferredError(ValueError("Operation on closed image"))
573573

574-
def _copy(self):
574+
def _copy(self) -> None:
575575
self.load()
576576
self.im = self.im.copy()
577577
self.pyaccess = None

src/PIL/ImageDraw.py

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
class ImageDraw:
4949
font = None
5050

51-
def __init__(self, im, mode=None):
51+
def __init__(self, im: Image.Image, mode: str | None = None) -> None:
5252
"""
5353
Create a drawing instance.
5454
@@ -115,7 +115,7 @@ def getfont(self):
115115
self.font = ImageFont.load_default()
116116
return self.font
117117

118-
def _getfont(self, font_size):
118+
def _getfont(self, font_size: float | None):
119119
if font_size is not None:
120120
from . import ImageFont
121121

@@ -124,7 +124,7 @@ def _getfont(self, font_size):
124124
font = self.getfont()
125125
return font
126126

127-
def _getink(self, ink, fill=None):
127+
def _getink(self, ink, fill=None) -> tuple[int | None, int | None]:
128128
if ink is None and fill is None:
129129
if self.fill:
130130
fill = self.ink
@@ -145,13 +145,13 @@ def _getink(self, ink, fill=None):
145145
fill = self.draw.draw_ink(fill)
146146
return ink, fill
147147

148-
def arc(self, xy, start, end, fill=None, width=1):
148+
def arc(self, xy, start, end, fill=None, width=1) -> None:
149149
"""Draw an arc."""
150150
ink, fill = self._getink(fill)
151151
if ink is not None:
152152
self.draw.draw_arc(xy, start, end, ink, width)
153153

154-
def bitmap(self, xy, bitmap, fill=None):
154+
def bitmap(self, xy, bitmap, fill=None) -> None:
155155
"""Draw a bitmap."""
156156
bitmap.load()
157157
ink, fill = self._getink(fill)
@@ -160,23 +160,23 @@ def bitmap(self, xy, bitmap, fill=None):
160160
if ink is not None:
161161
self.draw.draw_bitmap(xy, bitmap.im, ink)
162162

163-
def chord(self, xy, start, end, fill=None, outline=None, width=1):
163+
def chord(self, xy, start, end, fill=None, outline=None, width=1) -> None:
164164
"""Draw a chord."""
165165
ink, fill = self._getink(outline, fill)
166166
if fill is not None:
167167
self.draw.draw_chord(xy, start, end, fill, 1)
168168
if ink is not None and ink != fill and width != 0:
169169
self.draw.draw_chord(xy, start, end, ink, 0, width)
170170

171-
def ellipse(self, xy, fill=None, outline=None, width=1):
171+
def ellipse(self, xy, fill=None, outline=None, width=1) -> None:
172172
"""Draw an ellipse."""
173173
ink, fill = self._getink(outline, fill)
174174
if fill is not None:
175175
self.draw.draw_ellipse(xy, fill, 1)
176176
if ink is not None and ink != fill and width != 0:
177177
self.draw.draw_ellipse(xy, ink, 0, width)
178178

179-
def line(self, xy, fill=None, width=0, joint=None):
179+
def line(self, xy, fill=None, width=0, joint=None) -> None:
180180
"""Draw a line, or a connected sequence of line segments."""
181181
ink = self._getink(fill)[0]
182182
if ink is not None:
@@ -236,7 +236,7 @@ def coord_at_angle(coord, angle):
236236
]
237237
self.line(gap_coords, fill, width=3)
238238

239-
def shape(self, shape, fill=None, outline=None):
239+
def shape(self, shape, fill=None, outline=None) -> None:
240240
"""(Experimental) Draw a shape."""
241241
shape.close()
242242
ink, fill = self._getink(outline, fill)
@@ -245,29 +245,29 @@ def shape(self, shape, fill=None, outline=None):
245245
if ink is not None and ink != fill:
246246
self.draw.draw_outline(shape, ink, 0)
247247

248-
def pieslice(self, xy, start, end, fill=None, outline=None, width=1):
248+
def pieslice(self, xy, start, end, fill=None, outline=None, width=1) -> None:
249249
"""Draw a pieslice."""
250250
ink, fill = self._getink(outline, fill)
251251
if fill is not None:
252252
self.draw.draw_pieslice(xy, start, end, fill, 1)
253253
if ink is not None and ink != fill and width != 0:
254254
self.draw.draw_pieslice(xy, start, end, ink, 0, width)
255255

256-
def point(self, xy, fill=None):
256+
def point(self, xy, fill=None) -> None:
257257
"""Draw one or more individual pixels."""
258258
ink, fill = self._getink(fill)
259259
if ink is not None:
260260
self.draw.draw_points(xy, ink)
261261

262-
def polygon(self, xy, fill=None, outline=None, width=1):
262+
def polygon(self, xy, fill=None, outline=None, width=1) -> None:
263263
"""Draw a polygon."""
264264
ink, fill = self._getink(outline, fill)
265265
if fill is not None:
266266
self.draw.draw_polygon(xy, fill, 1)
267267
if ink is not None and ink != fill and width != 0:
268268
if width == 1:
269269
self.draw.draw_polygon(xy, ink, 0, width)
270-
else:
270+
elif self.im is not None:
271271
# To avoid expanding the polygon outwards,
272272
# use the fill as a mask
273273
mask = Image.new("1", self.im.size)
@@ -291,12 +291,12 @@ def polygon(self, xy, fill=None, outline=None, width=1):
291291

292292
def regular_polygon(
293293
self, bounding_circle, n_sides, rotation=0, fill=None, outline=None, width=1
294-
):
294+
) -> None:
295295
"""Draw a regular polygon."""
296296
xy = _compute_regular_polygon_vertices(bounding_circle, n_sides, rotation)
297297
self.polygon(xy, fill, outline, width)
298298

299-
def rectangle(self, xy, fill=None, outline=None, width=1):
299+
def rectangle(self, xy, fill=None, outline=None, width=1) -> None:
300300
"""Draw a rectangle."""
301301
ink, fill = self._getink(outline, fill)
302302
if fill is not None:
@@ -306,7 +306,7 @@ def rectangle(self, xy, fill=None, outline=None, width=1):
306306

307307
def rounded_rectangle(
308308
self, xy, radius=0, fill=None, outline=None, width=1, *, corners=None
309-
):
309+
) -> None:
310310
"""Draw a rounded rectangle."""
311311
if isinstance(xy[0], (list, tuple)):
312312
(x0, y0), (x1, y1) = xy
@@ -346,7 +346,7 @@ def rounded_rectangle(
346346
r = d // 2
347347
ink, fill = self._getink(outline, fill)
348348

349-
def draw_corners(pieslice):
349+
def draw_corners(pieslice) -> None:
350350
if full_x:
351351
# Draw top and bottom halves
352352
parts = (
@@ -431,12 +431,12 @@ def draw_corners(pieslice):
431431
right[3] -= r + 1
432432
self.draw.draw_rectangle(right, ink, 1)
433433

434-
def _multiline_check(self, text):
434+
def _multiline_check(self, text) -> bool:
435435
split_character = "\n" if isinstance(text, str) else b"\n"
436436

437437
return split_character in text
438438

439-
def _multiline_split(self, text):
439+
def _multiline_split(self, text) -> list[str | bytes]:
440440
split_character = "\n" if isinstance(text, str) else b"\n"
441441

442442
return text.split(split_character)
@@ -465,7 +465,7 @@ def text(
465465
embedded_color=False,
466466
*args,
467467
**kwargs,
468-
):
468+
) -> None:
469469
"""Draw text."""
470470
if embedded_color and self.mode not in ("RGB", "RGBA"):
471471
msg = "Embedded color supported only in RGB and RGBA modes"
@@ -497,7 +497,7 @@ def getink(fill):
497497
return fill
498498
return ink
499499

500-
def draw_text(ink, stroke_width=0, stroke_offset=None):
500+
def draw_text(ink, stroke_width=0, stroke_offset=None) -> None:
501501
mode = self.fontmode
502502
if stroke_width == 0 and embedded_color:
503503
mode = "RGBA"
@@ -547,7 +547,8 @@ def draw_text(ink, stroke_width=0, stroke_offset=None):
547547
ink_alpha = struct.pack("i", ink)[3]
548548
color.fillband(3, ink_alpha)
549549
x, y = coord
550-
self.im.paste(color, (x, y, x + mask.size[0], y + mask.size[1]), mask)
550+
if self.im is not None:
551+
self.im.paste(color, (x, y, x + mask.size[0], y + mask.size[1]), mask)
551552
else:
552553
self.draw.draw_bitmap(coord, mask, ink)
553554

@@ -584,7 +585,7 @@ def multiline_text(
584585
embedded_color=False,
585586
*,
586587
font_size=None,
587-
):
588+
) -> None:
588589
if direction == "ttb":
589590
msg = "ttb direction is unsupported for multiline text"
590591
raise ValueError(msg)
@@ -693,7 +694,7 @@ def textbbox(
693694
embedded_color=False,
694695
*,
695696
font_size=None,
696-
):
697+
) -> tuple[int, int, int, int]:
697698
"""Get the bounding box of a given string, in pixels."""
698699
if embedded_color and self.mode not in ("RGB", "RGBA"):
699700
msg = "Embedded color supported only in RGB and RGBA modes"
@@ -738,7 +739,7 @@ def multiline_textbbox(
738739
embedded_color=False,
739740
*,
740741
font_size=None,
741-
):
742+
) -> tuple[int, int, int, int]:
742743
if direction == "ttb":
743744
msg = "ttb direction is unsupported for multiline text"
744745
raise ValueError(msg)
@@ -777,7 +778,7 @@ def multiline_textbbox(
777778
elif anchor[1] == "d":
778779
top -= (len(lines) - 1) * line_spacing
779780

780-
bbox = None
781+
bbox: tuple[int, int, int, int] | None = None
781782

782783
for idx, line in enumerate(lines):
783784
left = xy[0]
@@ -828,7 +829,7 @@ def multiline_textbbox(
828829
return bbox
829830

830831

831-
def Draw(im, mode=None):
832+
def Draw(im: Image.Image, mode: str | None = None) -> ImageDraw:
832833
"""
833834
A simple 2D drawing interface for PIL images.
834835
@@ -876,7 +877,7 @@ def getdraw(im=None, hints=None):
876877
return im, handler
877878

878879

879-
def floodfill(image, xy, value, border=None, thresh=0):
880+
def floodfill(image: Image.Image, xy, value, border=None, thresh=0) -> None:
880881
"""
881882
(experimental) Fills a bounded region with a given color.
882883
@@ -932,7 +933,7 @@ def floodfill(image, xy, value, border=None, thresh=0):
932933
edge = new_edge
933934

934935

935-
def _compute_regular_polygon_vertices(bounding_circle, n_sides, rotation):
936+
def _compute_regular_polygon_vertices(bounding_circle, n_sides, rotation) -> list[tuple[float, float]]:
936937
"""
937938
Generate a list of vertices for a 2D regular polygon.
938939
@@ -982,7 +983,7 @@ def _compute_regular_polygon_vertices(bounding_circle, n_sides, rotation):
982983

983984
# 1.2 Check `bounding_circle` has an appropriate value
984985
if not isinstance(bounding_circle, (list, tuple)):
985-
msg = "bounding_circle should be a tuple"
986+
msg = "bounding_circle should be a sequence"
986987
raise TypeError(msg)
987988

988989
if len(bounding_circle) == 3:
@@ -1014,7 +1015,7 @@ def _compute_regular_polygon_vertices(bounding_circle, n_sides, rotation):
10141015
raise ValueError(msg)
10151016

10161017
# 2. Define Helper Functions
1017-
def _apply_rotation(point, degrees, centroid):
1018+
def _apply_rotation(point: list[float], degrees: float) -> tuple[int, int]:
10181019
return (
10191020
round(
10201021
point[0] * math.cos(math.radians(360 - degrees))
@@ -1030,11 +1031,11 @@ def _apply_rotation(point, degrees, centroid):
10301031
),
10311032
)
10321033

1033-
def _compute_polygon_vertex(centroid, polygon_radius, angle):
1034+
def _compute_polygon_vertex(angle: float) -> tuple[int, int]:
10341035
start_point = [polygon_radius, 0]
1035-
return _apply_rotation(start_point, angle, centroid)
1036+
return _apply_rotation(start_point, angle)
10361037

1037-
def _get_angles(n_sides, rotation):
1038+
def _get_angles(n_sides: int, rotation: float) -> list[float]:
10381039
angles = []
10391040
degrees = 360 / n_sides
10401041
# Start with the bottom left polygon vertex
@@ -1051,11 +1052,11 @@ def _get_angles(n_sides, rotation):
10511052

10521053
# 4. Compute Vertices
10531054
return [
1054-
_compute_polygon_vertex(centroid, polygon_radius, angle) for angle in angles
1055+
_compute_polygon_vertex(angle) for angle in angles
10551056
]
10561057

10571058

1058-
def _color_diff(color1, color2):
1059+
def _color_diff(color1, color2: float | tuple[int, ...]) -> float:
10591060
"""
10601061
Uses 1-norm distance to calculate difference between two values.
10611062
"""

src/PIL/ImageFont.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,7 @@ def load_path(filename):
872872
raise OSError(msg)
873873

874874

875-
def load_default(size=None):
875+
def load_default(size: float | None = None) -> FreeTypeFont | ImageFont:
876876
"""If FreeType support is available, load a version of Aileron Regular,
877877
https://dotcolon.net/font/aileron, with a more limited character set.
878878

0 commit comments

Comments
 (0)