Skip to content

Commit 71cff6d

Browse files
Improve type hints on public interface (#583)
* add missing return type hints * fix annotations (with note) * notes * ruff * improve hint * avoid issue with circular import * defer evalutation of the annotations * sort imports * improve hints * format * add `None` * Add `Literal` hints methods affected: - `lineCap` - `underline` - `strikethrough` - `writingDirection` - `text` - `textBox` - `textBoxBaselines` * improve hints * we can import PIL, so we can get this one back * avoid issue with circular import * sort imports * improve hints * improve docs * improve hints * fix test data a small change in booleanOperation causes this diff * promote resetVariations to explicit keyword argument this removes the fontVariations(None) deprecated option after 8 years. * promote `resetFeatures` to explicit keyword argument openTypeFeatures(None) no longer supported after 8 years of deprecation * Align all examples to use `newPage` instead of `size` * Revert "Align all examples to use `newPage` instead of `size`" This reverts commit 924b6c4. * align to the other scripts in the folder * update image * restore print block * fixing test * fixing test pdf --------- Co-authored-by: Frederik Berlaen <frederik@typemytype.com>
1 parent f396149 commit 71cff6d

19 files changed

Lines changed: 276 additions & 239 deletions

docs/content/text/textProperties.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ Text Properties
1010
.. autofunction:: drawBot.lineHeight
1111
.. autofunction:: drawBot.tracking
1212
.. autofunction:: drawBot.baselineShift
13-
.. autofunction:: drawBot.openTypeFeatures(frac=True, case=True, ...)
13+
.. autofunction:: drawBot.openTypeFeatures(frac=True, case=True, ..., resetFeatures=False)
1414
.. autofunction:: drawBot.listOpenTypeFeatures
15-
.. autofunction:: drawBot.fontVariations(wdth=0.6, wght=0.1, ...)
15+
.. autofunction:: drawBot.fontVariations(wdth=0.6, wght=0.1, ..., resetVariations=False)
1616
.. autofunction:: drawBot.listFontVariations
1717
.. autofunction:: drawBot.fontNamedInstance
1818
.. autofunction:: drawBot.listNamedInstances

drawBot/context/baseContext.py

Lines changed: 46 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -264,13 +264,13 @@ def _curveToOne(self, pt1, pt2, pt3):
264264
"""
265265
self._path.curveToPoint_controlPoint1_controlPoint2_(pt3, pt1, pt2)
266266

267-
def closePath(self):
267+
def closePath(self) -> None:
268268
"""
269269
Close the path.
270270
"""
271271
self._path.closePath()
272272

273-
def beginPath(self, identifier=None):
273+
def beginPath(self, identifier: str | None = None) -> None:
274274
"""
275275
Begin using the path as a so called point pen and start a new subpath.
276276
"""
@@ -285,9 +285,9 @@ def addPoint(
285285
segmentType: str | None = None,
286286
smooth: bool = False,
287287
name: str | None = None,
288-
identifier=None,
289-
**kwargs,
290-
):
288+
identifier: str | None = None,
289+
**kwargs: Any,
290+
) -> None:
291291
"""
292292
Use the path as a point pen and add a point to the current subpath. `beginPath` must
293293
have been called prior to adding points with `addPoint` calls.
@@ -303,7 +303,7 @@ def addPoint(
303303
**kwargs,
304304
)
305305

306-
def endPath(self):
306+
def endPath(self) -> None:
307307
"""
308308
End the current subpath. Calling this method has two distinct meanings depending
309309
on the context:
@@ -603,7 +603,7 @@ def controlPointBounds(self) -> BoundingBox | None:
603603
(x, y), (w, h) = self._path.controlPointBounds()
604604
return x, y, x + w, y + h
605605

606-
def optimizePath(self):
606+
def optimizePath(self) -> None:
607607
count = self._path.elementCount()
608608
if not count or self._path.elementAtIndex_(count - 1) != AppKit.NSMoveToBezierPathElement:
609609
return
@@ -630,13 +630,13 @@ def copy(self) -> Self:
630630
new.copyContextProperties(self)
631631
return new
632632

633-
def reverse(self):
633+
def reverse(self) -> None:
634634
"""
635635
Reverse the path direction
636636
"""
637637
self._path = self._path.bezierPathByReversingPath()
638638

639-
def appendPath(self, otherPath: Self):
639+
def appendPath(self, otherPath: Self) -> None:
640640
"""
641641
Append a path.
642642
"""
@@ -653,13 +653,13 @@ def __iadd__(self, other: Self) -> Self:
653653

654654
# transformations
655655

656-
def translate(self, x: float = 0, y: float = 0):
656+
def translate(self, x: float = 0, y: float = 0) -> None:
657657
"""
658658
Translate the path with a given offset.
659659
"""
660660
self.transform((1, 0, 0, 1, x, y))
661661

662-
def rotate(self, angle: float, center: Point = (0, 0)):
662+
def rotate(self, angle: float, center: Point = (0, 0)) -> None:
663663
"""
664664
Rotate the path around the `center` point (which is the origin by default) with a given angle in degrees.
665665
"""
@@ -668,7 +668,7 @@ def rotate(self, angle: float, center: Point = (0, 0)):
668668
s = math.sin(angle)
669669
self.transform((c, s, -s, c, 0, 0), center)
670670

671-
def scale(self, x: float = 1, y: float | None = None, center: Point = (0, 0)):
671+
def scale(self, x: float = 1, y: float | None = None, center: Point = (0, 0)) -> None:
672672
"""
673673
Scale the path with a given `x` (horizontal scale) and `y` (vertical scale).
674674
@@ -680,7 +680,7 @@ def scale(self, x: float = 1, y: float | None = None, center: Point = (0, 0)):
680680
y = x
681681
self.transform((x, 0, 0, y, 0, 0), center)
682682

683-
def skew(self, angle1: float, angle2: float = 0, center: Point = (0, 0)):
683+
def skew(self, angle1: float, angle2: float = 0, center: Point = (0, 0)) -> None:
684684
"""
685685
Skew the path with given `angle1` and `angle2`.
686686
@@ -692,7 +692,7 @@ def skew(self, angle1: float, angle2: float = 0, center: Point = (0, 0)):
692692
angle2 = math.radians(angle2)
693693
self.transform((1, math.tan(angle2), math.tan(angle1), 1, 0, 0), center)
694694

695-
def transform(self, transformMatrix: TransformTuple, center: Point = (0, 0)):
695+
def transform(self, transformMatrix: TransformTuple, center: Point = (0, 0)) -> None:
696696
"""
697697
Transform a path with a transform matrix (xy, xx, yy, yx, x, y).
698698
"""
@@ -1638,7 +1638,7 @@ def font(
16381638
font = getNSFontFromNameOrPath(fontNameOrPath, fontSize or 10, fontNumber)
16391639
return getFontName(font)
16401640

1641-
def fontNumber(self, fontNumber: int):
1641+
def fontNumber(self, fontNumber: int) -> None:
16421642
self._fontNumber = fontNumber
16431643

16441644
def fallbackFont(self, fontNameOrPath: SomePath, fontNumber: int = 0) -> str | None:
@@ -1656,17 +1656,17 @@ def fallbackFont(self, fontNameOrPath: SomePath, fontNumber: int = 0) -> str | N
16561656
self._fallbackFontNumber = fontNumber
16571657
return fontName
16581658

1659-
def fallbackFontNumber(self, fontNumber: int):
1659+
def fallbackFontNumber(self, fontNumber: int) -> None:
16601660
self._fallbackFontNumber = fontNumber
16611661

1662-
def fontSize(self, fontSize: float):
1662+
def fontSize(self, fontSize: float) -> None:
16631663
"""
16641664
Set the font size in points.
16651665
The default `fontSize` is 10pt.
16661666
"""
16671667
self._fontSize = fontSize
16681668

1669-
def fill(self, r: float | None = None, g: float | None = None, b: float | None = None, alpha: float = 1):
1669+
def fill(self, r: float | None = None, g: float | None = None, b: float | None = None, alpha: float = 1) -> None:
16701670
"""
16711671
Sets the fill color with a `red`, `green`, `blue` and `alpha` value.
16721672
Each argument must a value float between 0 and 1.
@@ -1678,7 +1678,7 @@ def fill(self, r: float | None = None, g: float | None = None, b: float | None =
16781678
self._fill = fill
16791679
self._cmykFill = None
16801680

1681-
def stroke(self, r: float | None = None, g: float | None = None, b: float | None = None, alpha: float = 1):
1681+
def stroke(self, r: float | None = None, g: float | None = None, b: float | None = None, alpha: float = 1) -> None:
16821682
"""
16831683
Sets the stroke color with a `red`, `green`, `blue` and `alpha` value.
16841684
Each argument must a value float between 0 and 1.
@@ -1697,7 +1697,7 @@ def cmykFill(
16971697
y: float | None = None,
16981698
k: float | None = None,
16991699
alpha: float = 1,
1700-
):
1700+
) -> None:
17011701
"""
17021702
Set a fill using a CMYK color before drawing a shape. This is handy if the file is intended for print.
17031703
@@ -1730,39 +1730,39 @@ def cmykStroke(
17301730
self._cmykStroke = cmykStroke
17311731
self._stroke = None
17321732

1733-
def strokeWidth(self, strokeWidth: float):
1733+
def strokeWidth(self, strokeWidth: float) -> None:
17341734
"""
17351735
Sets stroke width.
17361736
"""
17371737
self._strokeWidth = strokeWidth
17381738

1739-
def align(self, align: str):
1739+
def align(self, align: str) -> None:
17401740
"""
17411741
Sets the text alignment.
17421742
Possible `align` values are: `left`, `center` and `right`.
17431743
"""
17441744
self._align = align
17451745

1746-
def lineHeight(self, lineHeight: float):
1746+
def lineHeight(self, lineHeight: float) -> None:
17471747
"""
17481748
Set the line height.
17491749
"""
17501750
self._lineHeight = lineHeight
17511751

1752-
def tracking(self, tracking: float):
1752+
def tracking(self, tracking: float) -> None:
17531753
"""
17541754
Set the tracking between characters. It adds an absolute number of
17551755
points between the characters.
17561756
"""
17571757
self._tracking = tracking
17581758

1759-
def baselineShift(self, baselineShift: float):
1759+
def baselineShift(self, baselineShift: float) -> None:
17601760
"""
17611761
Set the shift of the baseline.
17621762
"""
17631763
self._baselineShift = baselineShift
17641764

1765-
def underline(self, underline: str | None):
1765+
def underline(self, underline: str | None) -> None:
17661766
"""
17671767
Set the underline value.
17681768
Underline must be `single`, `thick`, `double` or `None`.
@@ -1771,7 +1771,7 @@ def underline(self, underline: str | None):
17711771
raise DrawBotError("underline must be %s" % (", ".join(sorted(self._textUnderlineMap.keys()))))
17721772
self._underline = underline
17731773

1774-
def strikethrough(self, strikethrough: str | None):
1774+
def strikethrough(self, strikethrough: str | None) -> None:
17751775
"""
17761776
Set the strikethrough value.
17771777
Strikethrough must be `single`, `thick`, `double` or `None`.
@@ -1780,16 +1780,17 @@ def strikethrough(self, strikethrough: str | None):
17801780
raise DrawBotError("strikethrough must be %s" % (", ".join(sorted(self._textstrikethroughMap.keys()))))
17811781
self._strikethrough = strikethrough
17821782

1783-
def url(self, url: str | None):
1783+
def url(self, url: str | None) -> None:
17841784
"""
17851785
set the url value.
17861786
url must be a string or `None`
17871787
"""
17881788
self._url = url
17891789

1790-
def openTypeFeatures(self, *args: None, **features: bool) -> dict[str, bool]:
1790+
def openTypeFeatures(self, *, resetFeatures: bool = False, **features: bool) -> dict[str, bool]:
17911791
"""
17921792
Enable OpenType features and return the current openType features settings.
1793+
You can reset the default values with `openTypeFeatures(resetFeatures=True)`
17931794
17941795
If no arguments are given `openTypeFeatures()` will just return the current openType features settings.
17951796
@@ -1811,19 +1812,9 @@ def openTypeFeatures(self, *args: None, **features: bool) -> dict[str, bool]:
18111812
# draw the formatted string
18121813
text(t, (10, 80))
18131814
"""
1814-
if args and features:
1815-
raise DrawBotError("Can't combine positional arguments and keyword arguments")
1816-
if args:
1817-
if len(args) != 1:
1818-
raise DrawBotError("There can only be one positional argument")
1819-
if args[0] is not None:
1820-
raise DrawBotError("First positional argument can only be None")
1821-
warnings.warn("openTypeFeatures(None) is deprecated, use openTypeFeatures(resetFeatures=True) instead.")
1815+
if resetFeatures:
18221816
self._openTypeFeatures.clear()
1823-
else:
1824-
if features.pop("resetFeatures", False):
1825-
self._openTypeFeatures.clear()
1826-
self._openTypeFeatures.update(features)
1817+
self._openTypeFeatures.update(features)
18271818
return dict(self._openTypeFeatures)
18281819

18291820
def listOpenTypeFeatures(self, fontNameOrPath: SomePath | None = None, fontNumber: int = 0) -> list[str]:
@@ -1837,25 +1828,16 @@ def listOpenTypeFeatures(self, fontNameOrPath: SomePath | None = None, fontNumbe
18371828
font = getNSFontFromNameOrPath(fontNameOrPath, 10, fontNumber)
18381829
return openType.getFeatureTagsForFont(font)
18391830

1840-
def fontVariations(self, *args: None, **axes: float | bool) -> dict[str, float]:
1831+
def fontVariations(self, *, resetVariations: bool = False, **axes: float) -> dict[str, float]:
18411832
"""
18421833
Pick a variation by axes values and return the current font variations settings.
1834+
You can reset the default values with `fontVariations(resetVariations=True)`
18431835
18441836
If no arguments are given `fontVariations()` will just return the current font variations settings.
18451837
"""
1846-
if args and axes:
1847-
raise DrawBotError("Can't combine positional arguments and keyword arguments")
1848-
if args:
1849-
if len(args) != 1:
1850-
raise DrawBotError("There can only be one positional argument")
1851-
if args[0] is not None:
1852-
raise DrawBotError("First positional argument can only be None")
1853-
warnings.warn("fontVariations(None) is deprecated, use fontVariations(resetVariations=True) instead.")
1838+
if resetVariations:
18541839
self._fontVariations.clear()
1855-
else:
1856-
if axes.pop("resetVariations", False):
1857-
self._fontVariations.clear()
1858-
self._fontVariations.update(axes)
1840+
self._fontVariations.update(axes)
18591841
defaultVariations = self.listFontVariations()
18601842
currentVariation = {axis: data["defaultValue"] for axis, data in defaultVariations.items()}
18611843
currentVariation.update(self._fontVariations)
@@ -1908,7 +1890,7 @@ def listNamedInstances(self, fontNameOrPath: SomePath | None = None, fontNumber:
19081890
font = getNSFontFromNameOrPath(fontNameOrPath, 10, fontNumber)
19091891
return variation.getNamedInstancesForFont(font)
19101892

1911-
def tabs(self, tab: tuple[float, str] | None, *tabs: tuple[float, str]):
1893+
def tabs(self, tab: tuple[float, str] | None, *tabs: tuple[float, str]) -> None:
19121894
"""
19131895
Set tabs,tuples of (`float`, `alignment`)
19141896
Aligment can be `"left"`, `"center"`, `"right"` or any other character.
@@ -1932,7 +1914,7 @@ def tabs(self, tab: tuple[float, str] | None, *tabs: tuple[float, str]):
19321914
combinedTabs.extend(tabs)
19331915
self._tabs = combinedTabs
19341916

1935-
def indent(self, indent: float):
1917+
def indent(self, indent: float) -> None:
19361918
"""
19371919
Set indent of text left of the paragraph.
19381920
@@ -2005,7 +1987,7 @@ def indent(self, indent: float):
20051987
"""
20061988
self._indent = indent
20071989

2008-
def tailIndent(self, indent: float):
1990+
def tailIndent(self, indent: float) -> None:
20091991
"""
20101992
Set indent of text right of the paragraph.
20111993
@@ -2014,19 +1996,19 @@ def tailIndent(self, indent: float):
20141996
"""
20151997
self._tailIndent = indent
20161998

2017-
def firstLineIndent(self, indent: float):
1999+
def firstLineIndent(self, indent: float) -> None:
20182000
"""
20192001
Set indent of the text only for the first line.
20202002
"""
20212003
self._firstLineIndent = indent
20222004

2023-
def paragraphTopSpacing(self, value: float):
2005+
def paragraphTopSpacing(self, value: float) -> None:
20242006
"""
20252007
set paragraph spacing at the top.
20262008
"""
20272009
self._paragraphTopSpacing = value
20282010

2029-
def paragraphBottomSpacing(self, value: float):
2011+
def paragraphBottomSpacing(self, value: float) -> None:
20302012
"""
20312013
set paragraph spacing at the bottom.
20322014
"""
@@ -2729,11 +2711,11 @@ def language(self, language):
27292711
def writingDirection(self, direction):
27302712
self._state.text.writingDirection(direction)
27312713

2732-
def openTypeFeatures(self, *args: None, **features: dict[str, bool]) -> dict[str, bool]:
2733-
return self._state.text.openTypeFeatures(*args, **features)
2714+
def openTypeFeatures(self, *, resetFeatures: bool = False, **features: bool) -> dict[str, bool]:
2715+
return self._state.text.openTypeFeatures(resetFeatures=resetFeatures, **features)
27342716

2735-
def fontVariations(self, *args, **axes):
2736-
return self._state.text.fontVariations(*args, **axes)
2717+
def fontVariations(self, *, resetVariations: bool = False, **axes: float) -> dict[str, float]:
2718+
return self._state.text.fontVariations(resetVariations=resetVariations, **axes)
27372719

27382720
def fontNamedInstance(self, name, fontNameOrPath):
27392721
self._state.text.fontNamedInstance(name, fontNameOrPath)

drawBot/context/tools/imageObject.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
import AppKit # type: ignore
2-
import Quartz # type: ignore
3-
from math import radians
41
import os
52
from math import radians
6-
from typing import Any
7-
8-
import AppKit
93
from typing import Self
104

5+
import AppKit # type: ignore
6+
import Quartz # type: ignore
7+
118
from drawBot.aliases import BoundingBox, Point, RGBAColorTuple, Size, SomePath, TransformTuple
12-
from drawBot.context.baseContext import FormattedString
139
from drawBot.context.imageContext import _makeBitmapImageRep
1410
from drawBot.misc import DrawBotError, optimizePath
1511

0 commit comments

Comments
 (0)