diff --git a/Lib/fontParts/base/base.py b/Lib/fontParts/base/base.py index 19ddccb6..4e7c5c68 100644 --- a/Lib/fontParts/base/base.py +++ b/Lib/fontParts/base/base.py @@ -25,7 +25,6 @@ from fontParts.base import normalizers from fontParts.base.annotations import ( PairType, - CollectionType, PairCollectionType, SextupleCollectionType, IntFloatType, diff --git a/Lib/fontParts/base/font.py b/Lib/fontParts/base/font.py index 80c581c6..53016c8a 100644 --- a/Lib/fontParts/base/font.py +++ b/Lib/fontParts/base/font.py @@ -131,8 +131,8 @@ def copyData(self, source: BaseFont) -> None: else: layer = self.newLayer(layerName) layer.copyData(source.getLayer(layerName)) - for guideline in self.guidelines: - self.appendGuideline(guideline) + for guideline in source.guidelines: + self.appendGuideline(guideline=guideline) super(BaseFont, self).copyData(source) # --------------- @@ -293,7 +293,7 @@ def _save( self, path: Optional[str], showProgress: bool, - formatVersion: Optional[float], + formatVersion: Optional[int], fileStructure: Optional[str], **kwargs: Any, ) -> None: @@ -1843,11 +1843,11 @@ def appendGuideline( def _appendGuideline( # type: ignore[return] self, - position: Optional[PairCollectionType[IntFloatType]], + position: PairCollectionType[IntFloatType], angle: Optional[float], name: Optional[str], color: Optional[QuadrupleCollectionType[IntFloatType]], - **kwargs, + **kwargs: Any, ) -> BaseGuideline: r"""Append a new guideline to the native font. diff --git a/Lib/fontParts/base/glyph.py b/Lib/fontParts/base/glyph.py index 9c3f0ef9..5f050ab8 100644 --- a/Lib/fontParts/base/glyph.py +++ b/Lib/fontParts/base/glyph.py @@ -308,7 +308,7 @@ def _set_base_unicodes(self, value: CollectionType[int]) -> None: value = normalizers.normalizeGlyphUnicodes(value) self._set_unicodes(value) - def _get_unicodes(self) -> Tuple[int, ...]: # type: ignore[return] + def _get_unicodes(self) -> CollectionType[int]: # type: ignore[return] """Get the Unicode values assigned to the glyph. This is the environment implementation of @@ -3232,10 +3232,11 @@ def _get_base_image(self) -> BaseImage: image.glyph = self return image - def _get_image(self) -> BaseImage: # type: ignore[return] + def _get_image(self) -> Optional[BaseImage]: # type: ignore[return] """Get the image for the native glyph. - :return: The :class:`BaseImage` subclass instance belonging to the glyph. + :return: The :class:`BaseImage` subclass instance belonging to the glyph, + or :obj:`None` if the glyph has no image. :raises NotImplementedError: If the method has not been overridden by a subclass. diff --git a/Lib/fontParts/base/groups.py b/Lib/fontParts/base/groups.py index c5763ef8..c819a470 100644 --- a/Lib/fontParts/base/groups.py +++ b/Lib/fontParts/base/groups.py @@ -9,9 +9,9 @@ if TYPE_CHECKING: from fontParts.base.font import BaseFont - from fontparts.base import BaseItems - from fontparts.base import BaseKeys - from fontparts.base import BaseValues + from fontParts.base.base import BaseKeys + from fontParts.base.base import BaseItems + from fontParts.base.base import BaseValues ValueType = Tuple[str, ...] GroupsDict = Dict[str, ValueType] diff --git a/Lib/fontParts/base/guideline.py b/Lib/fontParts/base/guideline.py index 37e4a0b7..efe4a690 100644 --- a/Lib/fontParts/base/guideline.py +++ b/Lib/fontParts/base/guideline.py @@ -535,7 +535,7 @@ def _set_name(self, value: Optional[str]) -> None: """, ) - def _get_base_color(self) -> Optional[Color]: + def _get_base_color(self) -> Optional[QuadrupleType[float]]: value = self._get_color() if value is not None: value = Color(value) @@ -548,7 +548,7 @@ def _set_base_color( value = normalizers.normalizeColor(value) self._set_color(value) - def _get_color(self) -> Optional[QuadrupleCollectionType[IntFloatType]]: + def _get_color(self) -> Optional[QuadrupleType[float]]: """Get the native guideline's color. This is the environment implementation of the :attr:`BaseGuideline.color` diff --git a/Lib/fontParts/base/layer.py b/Lib/fontParts/base/layer.py index 298b3bd4..1d9f6e27 100644 --- a/Lib/fontParts/base/layer.py +++ b/Lib/fontParts/base/layer.py @@ -804,19 +804,21 @@ def _set_name(self, value: str, **kwargs: Any) -> None: """, ) - def _get_base_color(self) -> QuadrupleCollectionType[IntFloatType]: + def _get_base_color(self) -> Optional[QuadrupleCollectionType[IntFloatType]]: value = self._get_color() if value is not None: value = normalizers.normalizeColor(value) value = Color(value) return value - def _set_base_color(self, value: QuadrupleCollectionType[IntFloatType]) -> None: + def _set_base_color( + self, value: Optional[QuadrupleCollectionType[IntFloatType]] + ) -> None: if value is not None: value = normalizers.normalizeColor(value) self._set_color(value) - def _get_color(self) -> QuadrupleCollectionType[IntFloatType]: # type: ignore[return] + def _get_color(self) -> Optional[QuadrupleCollectionType[IntFloatType]]: # type: ignore[return] """Get the color of the layer. This is the environment implementation of diff --git a/Lib/fontParts/base/lib.py b/Lib/fontParts/base/lib.py index 5f7a96d9..61473cbc 100644 --- a/Lib/fontParts/base/lib.py +++ b/Lib/fontParts/base/lib.py @@ -10,10 +10,10 @@ if TYPE_CHECKING: from fontParts.base.glyph import BaseGlyph from fontParts.base.font import BaseFont - from fontparts.base.layer import BaseLayer - from fontparts.base import BaseItems - from fontparts.base import BaseKeys - from fontparts.base import BaseValues + from fontParts.base.layer import BaseLayer + from fontParts.base.base import BaseItems + from fontParts.base.base import BaseValues + from fontParts.base.base import BaseKeys class BaseLib(BaseDict, DeprecatedLib, RemovedLib): diff --git a/Lib/fontParts/fontshell/anchor.py b/Lib/fontParts/fontshell/anchor.py index a06ce64c..b5694260 100644 --- a/Lib/fontParts/fontshell/anchor.py +++ b/Lib/fontParts/fontshell/anchor.py @@ -1,17 +1,26 @@ +from __future__ import annotations +from typing import cast, Optional + import defcon from fontParts.base import BaseAnchor +from fontParts.base.annotations import ( + QuadrupleType, + QuadrupleCollectionType, + IntFloatType, +) from fontParts.fontshell.base import RBaseObject class RAnchor(RBaseObject, BaseAnchor): wrapClass = defcon.Anchor - def _init(self, wrap=None): - if wrap is None: - wrap = self.wrapClass() - wrap.x = 0 - wrap.y = 0 - super(RAnchor, self)._init(wrap=wrap) + def _init(self, pathOrObject: Optional[defcon.Anchor] = None) -> None: + if self.wrapClass is not None: + if pathOrObject is None: + pathOrObject = self.wrapClass() + pathOrObject.x = 0 + pathOrObject.y = 0 + super(RAnchor, self)._init(pathOrObject=pathOrObject) # -------- # Position @@ -19,18 +28,18 @@ def _init(self, wrap=None): # x - def _get_x(self): + def _get_x(self) -> float: return self.naked().x - def _set_x(self, value): + def _set_x(self, value: float) -> None: self.naked().x = value # y - def _get_y(self): + def _get_y(self) -> float: return self.naked().y - def _set_y(self, value): + def _set_y(self, value: float) -> None: self.naked().y = value # -------------- @@ -39,32 +48,29 @@ def _set_y(self, value): # identifier - def _get_identifier(self): - anchor = self.naked() - return anchor.identifier + def _get_identifier(self) -> Optional[str]: + return self.naked().identifier - def _getIdentifier(self): - anchor = self.naked() - return anchor.generateIdentifier() + def _getIdentifier(self) -> str: + return self.naked().generateIdentifier() - def _setIdentifier(self, value): + def _setIdentifier(self, value: str) -> None: self.naked().identifier = value # name - def _get_name(self): + def _get_name(self) -> Optional[str]: return self.naked().name - def _set_name(self, value): + def _set_name(self, value: str) -> None: self.naked().name = value # color - def _get_color(self): - value = self.naked().color - if value is not None: - value = tuple(value) - return value + def _get_color(self) -> Optional[QuadrupleType[float]]: + return self.naked().color - def _set_color(self, value): + def _set_color( + self, value: Optional[QuadrupleCollectionType[IntFloatType]] + ) -> None: self.naked().color = value diff --git a/Lib/fontParts/fontshell/base.py b/Lib/fontParts/fontshell/base.py index 258613d8..00f9244a 100644 --- a/Lib/fontParts/fontshell/base.py +++ b/Lib/fontParts/fontshell/base.py @@ -1,16 +1,23 @@ -class RBaseObject(object): - wrapClass = None +from __future__ import annotations +from typing import Generic, Optional, Type, TypeVar - def _init(self, wrap=None): - if wrap is None and self.wrapClass is not None: - wrap = self.wrapClass() - if wrap is not None: - self._wrapped = wrap +RBaseObjectType = TypeVar("RBaseObjectType", bound="RBaseObject") - def changed(self): + +class RBaseObject(Generic[RBaseObjectType]): + wrapClass: Optional[Type[RBaseObjectType]] = None + dirty: bool + + def _init(self, pathOrObject: Optional[RBaseObjectType] = None) -> None: + if pathOrObject is None and self.wrapClass is not None: + pathOrObject = self.wrapClass() # pylint: disable=E1102 + if pathOrObject is not None: + self._wrapped = pathOrObject + + def changed(self) -> None: self.naked().dirty = True - def naked(self): + def naked(self) -> RBaseObjectType: if hasattr(self, "_wrapped"): return self._wrapped - return None + return None # type: ignore[return-value] diff --git a/Lib/fontParts/fontshell/component.py b/Lib/fontParts/fontshell/component.py index 6ab5dd41..d15b8fac 100644 --- a/Lib/fontParts/fontshell/component.py +++ b/Lib/fontParts/fontshell/component.py @@ -1,10 +1,18 @@ +from __future__ import annotations +from typing import Optional, Type + import defcon from fontParts.base import BaseComponent +from fontParts.base.annotations import ( + SextupleType, + SextupleCollectionType, + IntFloatType, +) from fontParts.fontshell.base import RBaseObject class RComponent(RBaseObject, BaseComponent): - wrapClass = defcon.Component + wrapClass: Type[defcon.Component] = defcon.Component # ---------- # Attributes @@ -12,19 +20,27 @@ class RComponent(RBaseObject, BaseComponent): # baseGlyph - def _get_baseGlyph(self): - return self.naked().baseGlyph + def _get_baseGlyph(self) -> Optional[str]: + component = self.naked() + return component.baseGlyph if component else None - def _set_baseGlyph(self, value): - self.naked().baseGlyph = value + def _set_baseGlyph(self, value: str) -> None: + component = self.naked() + if component is not None: + component.baseGlyph = value # transformation - def _get_transformation(self): - return self.naked().transformation + def _get_transformation(self) -> SextupleType[float]: + component = self.naked() + if component is None: + raise ValueError("Naked cannot be None.") + return component.transformation - def _set_transformation(self, value): - self.naked().transformation = value + def _set_transformation(self, value: SextupleCollectionType[IntFloatType]) -> None: + component = self.naked() + if component is not None: + component.transformation = value # -------------- # Identification @@ -44,14 +60,20 @@ def _set_index(self, value): def _get_identifier(self): component = self.naked() + if component is None: + return None return component.identifier def _getIdentifier(self): component = self.naked() + if component is None: + return None return component.generateIdentifier() def _setIdentifier(self, value): - self.naked().identifier = value + component = self.naked() + if component is not None: + component.identifier = value # ------------- # Normalization diff --git a/Lib/fontParts/fontshell/contour.py b/Lib/fontParts/fontshell/contour.py index 3ee24dd9..2952dd7f 100644 --- a/Lib/fontParts/fontshell/contour.py +++ b/Lib/fontParts/fontshell/contour.py @@ -1,10 +1,17 @@ +from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Any + import defcon from fontParts.base import BaseContour +from fontParts.base.annotations import PairCollectionType, QuadrupleType, IntFloatType from fontParts.fontshell.base import RBaseObject from fontParts.fontshell.point import RPoint from fontParts.fontshell.segment import RSegment from fontParts.fontshell.bPoint import RBPoint +if TYPE_CHECKING: + from fontParts.base import BasePoint + class RContour(RBaseObject, BaseContour): wrapClass = defcon.Contour @@ -18,101 +25,103 @@ class RContour(RBaseObject, BaseContour): # index - def _set_index(self, value): + def _set_index(self, value: int) -> None: contour = self.naked() glyph = contour.glyph - glyph.removeContour(contour) - glyph.insertContour(value, contour) + if glyph is not None: + glyph.removeContour(contour) + glyph.insertContour(value, contour) # identifier - def _get_identifier(self): - contour = self.naked() - return contour.identifier + def _get_identifier(self) -> Optional[str]: + return self.naked().identifier - def _getIdentifier(self): - contour = self.naked() - return contour.generateIdentifier() + def _getIdentifier(self) -> str: + return self.naked().generateIdentifier() - def _getIdentifierForPoint(self, point): + def _getIdentifierForPoint(self, point: BasePoint) -> str: contour = self.naked() - point = point.naked() - return contour.generateIdentifierForPoint(point) + nakedPoint = point.naked() + return contour.generateIdentifierForPoint(nakedPoint) # ---- # Open # ---- - def _get_open(self): + def _get_open(self) -> bool: return self.naked().open # ------ # Bounds # ------ - def _get_bounds(self): + def _get_bounds(self) -> Optional[QuadrupleType[float]]: return self.naked().bounds # ---- # Area # ---- - def _get_area(self): + def _get_area(self) -> Optional[float]: return self.naked().area # --------- # Direction # --------- - def _get_clockwise(self): + def _get_clockwise(self) -> bool: return self.naked().clockwise - def _reverse(self, **kwargs): + def _reverse(self, **kwargs: Any) -> None: self.naked().reverse() # ------------------------ # Point and Contour Inside # ------------------------ - def _pointInside(self, point): + def _pointInside(self, point: PairCollectionType[IntFloatType]) -> bool: return self.naked().pointInside(point) - def _contourInside(self, otherContour): + def _contourInside(self, otherContour: BaseContour) -> bool: return self.naked().contourInside(otherContour.naked(), segmentLength=5) # ------ # Points # ------ - def _lenPoints(self, **kwargs): + def _lenPoints(self, **kwargs: Any) -> int: return len(self.naked()) - def _getPoint(self, index, **kwargs): + def _getPoint(self, index: int, **kwargs: Any) -> RPoint: contour = self.naked() point = contour[index] return self.pointClass(point) def _insertPoint( self, - index, - position, - type=None, - smooth=None, - name=None, - identifier=None, - **kwargs, - ): + index: int, + position: PairCollectionType[IntFloatType], + type: Optional[str] = None, + smooth: Optional[bool] = None, + name: Optional[str] = None, + identifier: Optional[str] = None, + **kwargs: Any, + ) -> None: point = self.pointClass() point.x = position[0] point.y = position[1] point.type = type point.smooth = smooth point.name = name - point = point.naked() + nakedPoint = point.naked() + if nakedPoint is not None: + point = nakedPoint point.identifier = identifier - self.naked().insertPoint(index, point) + contour = self.naked() + contour.insertPoint(index, point) - def _removePoint(self, index, preserveCurve, **kwargs): + def _removePoint(self, index: int, preserveCurve: bool, **kwargs: Any) -> None: contour = self.naked() point = contour[index] contour.removePoint(point) diff --git a/Lib/fontParts/fontshell/features.py b/Lib/fontParts/fontshell/features.py index 30fb7d37..0dc12ad2 100644 --- a/Lib/fontParts/fontshell/features.py +++ b/Lib/fontParts/fontshell/features.py @@ -1,3 +1,6 @@ +from __future__ import annotations +from typing import Optional + import defcon from fontParts.base import BaseFeatures from fontParts.fontshell.base import RBaseObject @@ -6,8 +9,10 @@ class RFeatures(RBaseObject, BaseFeatures): wrapClass = defcon.Features - def _get_text(self): - return self.naked().text + def _get_text(self) -> Optional[str]: + features = self.naked() + return features.text - def _set_text(self, value): - self.naked().text = value + def _set_text(self, value: str) -> None: + features = self.naked() + features.text = value diff --git a/Lib/fontParts/fontshell/font.py b/Lib/fontParts/fontshell/font.py index cd4d22bb..3e9d3841 100644 --- a/Lib/fontParts/fontshell/font.py +++ b/Lib/fontParts/fontshell/font.py @@ -1,5 +1,14 @@ -import defcon +from __future__ import annotations +from typing import Any, Optional, Tuple, Union import os + +import defcon +from fontParts.base.annotations import ( + CollectionType, + PairCollectionType, + QuadrupleCollectionType, + IntFloatType, +) from fontParts.base import BaseFont from fontParts.fontshell.base import RBaseObject from fontParts.fontshell.info import RInfo @@ -27,39 +36,43 @@ class RFont(RBaseObject, BaseFont): # Initialize - def _init(self, pathOrObject=None, showInterface=True, **kwargs): - if pathOrObject is None: - font = self.wrapClass() - elif isinstance(pathOrObject, str): - font = self.wrapClass(pathOrObject) - elif hasattr(pathOrObject, "__fspath__"): - font = self.wrapClass(os.fspath(pathOrObject)) - else: - font = pathOrObject - self._wrapped = font + def _init( + self, + pathOrObject: Optional[Union[str, os.PathLike, defcon.Font]] = None, + showInterface: bool = True, + **kwargs: Any, + ) -> None: + if self.wrapClass is not None: + if pathOrObject is None: + font = self.wrapClass() + elif isinstance(pathOrObject, (str, os.PathLike)): + font = self.wrapClass(os.fspath(pathOrObject)) + else: + font = pathOrObject + self._wrapped = font # path - def _get_path(self, **kwargs): + def _get_path(self, **kwargs: Any) -> Optional[str]: return self.naked().path # save def _save( self, - path=None, - showProgress=False, - formatVersion=None, - fileStructure=None, - **kwargs, - ): + path: Optional[str] = None, + showProgress: bool = False, + formatVersion: Optional[int] = None, + fileStructure: Optional[str] = None, + **kwargs: Any, + ) -> None: self.naked().save( path=path, formatVersion=formatVersion, structure=fileStructure ) # close - def _close(self, **kwargs): + def _close(self, **kwargs: Any) -> None: del self._wrapped # ----------- @@ -68,72 +81,80 @@ def _close(self, **kwargs): # info - def _get_info(self): - return self.infoClass(wrap=self.naked().info) + def _get_info(self) -> RInfo: + return self.infoClass(pathOrObject=self.naked().info) # groups - def _get_groups(self): - return self.groupsClass(wrap=self.naked().groups) + def _get_groups(self) -> RGroups: + return self.groupsClass(pathOrObject=self.naked().groups) # kerning - def _get_kerning(self): - return self.kerningClass(wrap=self.naked().kerning) + def _get_kerning(self) -> RKerning: + return self.kerningClass(pathOrObject=self.naked().kerning) # features - def _get_features(self): - return self.featuresClass(wrap=self.naked().features) + def _get_features(self) -> RFeatures: + return self.featuresClass(pathOrObject=self.naked().features) # lib - def _get_lib(self): - return self.libClass(wrap=self.naked().lib) + def _get_lib(self) -> RLib: + return self.libClass(pathOrObject=self.naked().lib) # tempLib - def _get_tempLib(self): - return self.libClass(wrap=self.naked().tempLib) + def _get_tempLib(self) -> RLib: + return self.libClass(pathOrObject=self.naked().tempLib) # ------ # Layers # ------ - def _get_layers(self, **kwargs): - return [self.layerClass(wrap=layer) for layer in self.naked().layers] + def _get_layers(self, **kwargs: Any) -> Tuple[RLayer, ...]: + return tuple( + self.layerClass(pathOrObject=layer) for layer in self.naked().layers + ) # order - def _get_layerOrder(self, **kwargs): + def _get_layerOrder(self, **kwargs: Any) -> Tuple[str, ...]: return self.naked().layers.layerOrder - def _set_layerOrder(self, value, **kwargs): + def _set_layerOrder(self, value: CollectionType[str], **kwargs: Any) -> None: self.naked().layers.layerOrder = value # default layer - def _get_defaultLayerName(self): + def _get_defaultLayerName(self) -> str: return self.naked().layers.defaultLayer.name - def _set_defaultLayerName(self, value, **kwargs): + def _set_defaultLayerName(self, value: str, **kwargs: Any) -> None: + font = self.naked() for layer in self.layers: if layer.name == value: break layer = layer.naked() - self.naked().layers.defaultLayer = layer + font.layers.defaultLayer = layer # new - def _newLayer(self, name, color, **kwargs): + def _newLayer( + self, + name: str, + color: Optional[QuadrupleCollectionType[IntFloatType]], + **kwargs: Any, + ) -> RLayer: layers = self.naked().layers layer = layers.newLayer(name) layer.color = color - return self.layerClass(wrap=layer) + return self.layerClass(pathOrObject=layer) # remove - def _removeLayer(self, name, **kwargs): + def _removeLayer(self, name: str, **kwargs: Any) -> None: layers = self.naked().layers del layers[name] @@ -141,36 +162,46 @@ def _removeLayer(self, name, **kwargs): # Glyphs # ------ - def _get_glyphOrder(self): + def _get_glyphOrder(self) -> Tuple[str, ...]: return self.naked().glyphOrder - def _set_glyphOrder(self, value): + def _set_glyphOrder(self, value: CollectionType[str]) -> None: self.naked().glyphOrder = value # ---------- # Guidelines # ---------- - def _lenGuidelines(self, **kwargs): + def _lenGuidelines(self, **kwargs: Any) -> int: return len(self.naked().guidelines) - def _getGuideline(self, index, **kwargs): + def _getGuideline(self, index: int, **kwargs: Any) -> RGuideline: guideline = self.naked().guidelines[index] return self.guidelineClass(guideline) def _appendGuideline( - self, position, angle, name=None, color=None, identifier=None, **kwargs - ): + self, + position: PairCollectionType[IntFloatType], + angle: Optional[float], + name: Optional[str] = None, + color: Optional[QuadrupleCollectionType[IntFloatType]] = None, + identifier: Optional[str] = None, + **kwargs: Any, + ) -> RGuideline: + font = self.naked() guideline = self.guidelineClass().naked() + if guideline is None: + raise ValueError("Guideline cannot be None.") guideline.x = position[0] guideline.y = position[1] guideline.angle = angle guideline.name = name guideline.color = color guideline.identifier = identifier - self.naked().appendGuideline(guideline) + font.appendGuideline(guideline) return self.guidelineClass(guideline) - def _removeGuideline(self, index, **kwargs): - guideline = self.naked().guidelines[index] - self.naked().removeGuideline(guideline) + def _removeGuideline(self, index: int, **kwargs: Any) -> None: + font = self.naked() + guideline = font.guidelines[index] + font.removeGuideline(guideline) diff --git a/Lib/fontParts/fontshell/glyph.py b/Lib/fontParts/fontshell/glyph.py index 333177c8..b2e4a35e 100644 --- a/Lib/fontParts/fontshell/glyph.py +++ b/Lib/fontParts/fontshell/glyph.py @@ -1,6 +1,17 @@ +from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Any, Union + import defcon import booleanOperations from fontParts.base import BaseGlyph +from fontParts.base.annotations import ( + CollectionType, + PairCollectionType, + QuadrupleType, + QuadrupleCollectionType, + SextupleCollectionType, + IntFloatType, +) from fontParts.base.errors import FontPartsError from fontParts.fontshell.base import RBaseObject from fontParts.fontshell.contour import RContour @@ -15,6 +26,14 @@ writeGlyphToString, ) +if TYPE_CHECKING: + from fontParts.base.image import BaseImage + from fontTools.pens.pointPen import SegmentToPointPen + from defcon.pens.glyphObjectPointPen import ( + GlyphObjectPointPen, + GlyphObjectLoadingPointPen, + ) + class RGlyph(RBaseObject, BaseGlyph): wrapClass = defcon.Glyph @@ -31,18 +50,18 @@ class RGlyph(RBaseObject, BaseGlyph): # Name - def _get_name(self): + def _get_name(self) -> str: return self.naked().name - def _set_name(self, value): + def _set_name(self, value: str) -> None: self.naked().name = value # Unicodes - def _get_unicodes(self): + def _get_unicodes(self) -> CollectionType[int]: return self.naked().unicodes - def _set_unicodes(self, value): + def _set_unicodes(self, value: CollectionType[int]) -> None: self.naked().unicodes = value # ------- @@ -51,70 +70,66 @@ def _set_unicodes(self, value): # horizontal - def _get_width(self): + def _get_width(self) -> IntFloatType: return self.naked().width - def _set_width(self, value): + def _set_width(self, value: IntFloatType) -> None: self.naked().width = value - def _get_leftMargin(self): + def _get_leftMargin(self) -> Optional[IntFloatType]: return self.naked().leftMargin - def _set_leftMargin(self, value): - naked = self.naked() - naked.leftMargin = value + def _set_leftMargin(self, value: IntFloatType) -> None: + self.naked().leftMargin = value - def _get_rightMargin(self): + def _get_rightMargin(self) -> Optional[IntFloatType]: return self.naked().rightMargin - def _set_rightMargin(self, value): - naked = self.naked() - naked.rightMargin = value + def _set_rightMargin(self, value: IntFloatType) -> None: + self.naked().rightMargin = value # vertical - def _get_height(self): + def _get_height(self) -> IntFloatType: return self.naked().height - def _set_height(self, value): + def _set_height(self, value: IntFloatType) -> None: self.naked().height = value - def _get_bottomMargin(self): + def _get_bottomMargin(self) -> Optional[IntFloatType]: return self.naked().bottomMargin - def _set_bottomMargin(self, value): - naked = self.naked() - naked.bottomMargin = value + def _set_bottomMargin(self, value: IntFloatType) -> None: + self.naked().bottomMargin = value - def _get_topMargin(self): + def _get_topMargin(self) -> Optional[IntFloatType]: return self.naked().topMargin - def _set_topMargin(self, value): - naked = self.naked() - naked.topMargin = value + def _set_topMargin(self, value: IntFloatType) -> None: + self.naked().topMargin = value # ------ # Bounds # ------ - def _get_bounds(self): + def _get_bounds(self) -> Optional[QuadrupleType[IntFloatType]]: return self.naked().bounds # ---- # Area # ---- - def _get_area(self): + def _get_area(self) -> Optional[float]: return self.naked().area # ---- # Pens # ---- - def getPen(self): + def getPen(self) -> SegmentToPointPen: return self.naked().getPen() - def getPointPen(self): + def getPointPen(self) -> Union[GlyphObjectPointPen, GlyphObjectLoadingPointPen]: return self.naked().getPointPen() # ----------------------------------------- @@ -123,20 +138,19 @@ def getPointPen(self): # Contours - def _lenContours(self, **kwargs): + def _lenContours(self, **kwargs: Any) -> int: return len(self.naked()) - def _getContour(self, index, **kwargs): - glyph = self.naked() - contour = glyph[index] + def _getContour(self, index: int, **kwargs: Any) -> RContour: + contour = self.naked()[index] return self.contourClass(contour) - def _removeContour(self, index, **kwargs): + def _removeContour(self, index: int, **kwargs: Any) -> None: glyph = self.naked() contour = glyph[index] glyph.removeContour(contour) - def _removeOverlap(self, **kwargs): + def _removeOverlap(self, **kwargs: Any) -> None: if len(self): contours = list(self) for contour in contours: @@ -152,40 +166,48 @@ def _removeOverlap(self, **kwargs): ) booleanOperations.union(contours, self.getPointPen()) - def _correctDirection(self, trueType=False, **kwargs): + def _correctDirection(self, trueType: bool = False, **kwargs: Any) -> None: self.naked().correctContourDirection(trueType=trueType) # Components - def _lenComponents(self, **kwargs): + def _lenComponents(self, **kwargs: Any) -> int: return len(self.naked().components) - def _getComponent(self, index, **kwargs): - glyph = self.naked() - component = glyph.components[index] + def _getComponent(self, index: int, **kwargs: Any) -> RComponent: + component = self.naked().components[index] return self.componentClass(component) - def _removeComponent(self, index, **kwargs): + def _removeComponent(self, index: int, **kwargs: Any) -> None: glyph = self.naked() component = glyph.components[index] glyph.removeComponent(component) # Anchors - def _lenAnchors(self, **kwargs): + def _lenAnchors(self, **kwargs: Any) -> int: return len(self.naked().anchors) - def _getAnchor(self, index, **kwargs): - glyph = self.naked() - anchor = glyph.anchors[index] + def _getAnchor(self, index: int, **kwargs: Any) -> RAnchor: + anchor = self.naked().anchors[index] return self.anchorClass(anchor) - def _appendAnchor(self, name, position=None, color=None, identifier=None, **kwargs): + def _appendAnchor( + self, + name: str, + position: Optional[PairCollectionType[IntFloatType]] = None, + color: Optional[QuadrupleCollectionType[IntFloatType]] = None, + identifier: Optional[str] = None, + **kwargs: Any, + ) -> RAnchor: glyph = self.naked() anchor = self.anchorClass().naked() + if anchor is None: + raise ValueError("Anchor cannot be None") anchor.name = name - anchor.x = position[0] - anchor.y = position[1] + if position is not None: + anchor.x = position[0] + anchor.y = position[1] anchor.color = color anchor.identifier = identifier glyph.appendAnchor(anchor) @@ -193,26 +215,33 @@ def _appendAnchor(self, name, position=None, color=None, identifier=None, **kwar wrapped.glyph = self return wrapped - def _removeAnchor(self, index, **kwargs): + def _removeAnchor(self, index: int, **kwargs: Any) -> None: glyph = self.naked() anchor = glyph.anchors[index] glyph.removeAnchor(anchor) # Guidelines - def _lenGuidelines(self, **kwargs): + def _lenGuidelines(self, **kwargs: Any) -> int: return len(self.naked().guidelines) - def _getGuideline(self, index, **kwargs): - glyph = self.naked() - guideline = glyph.guidelines[index] + def _getGuideline(self, index: int, **kwargs: Any) -> RGuideline: + guideline = self.naked().guidelines[index] return self.guidelineClass(guideline) def _appendGuideline( - self, position, angle, name=None, color=None, identifier=None, **kwargs - ): + self, + position: Optional[PairCollectionType[IntFloatType]], + angle: float, + name: Optional[str] = None, + color: Optional[QuadrupleCollectionType[IntFloatType]] = None, + identifier: Optional[str] = None, + **kwargs: Any, + ) -> RGuideline: glyph = self.naked() guideline = self.guidelineClass().naked() + if guideline is None: + raise ValueError("Guideline cannot be None") guideline.x = position[0] guideline.y = position[1] guideline.angle = angle @@ -222,7 +251,7 @@ def _appendGuideline( glyph.appendGuideline(guideline) return self.guidelineClass(guideline) - def _removeGuideline(self, index, **kwargs): + def _removeGuideline(self, index: int, **kwargs: Any) -> None: glyph = self.naked() guideline = glyph.guidelines[index] glyph.removeGuideline(guideline) @@ -233,7 +262,7 @@ def _removeGuideline(self, index, **kwargs): # new - def _newLayer(self, name, **kwargs): + def _newLayer(self, name: str, **kwargs: Any) -> RGlyph: layerName = name glyphName = self.name font = self.font @@ -246,7 +275,7 @@ def _newLayer(self, name, **kwargs): # remove - def _removeLayer(self, name, **kwargs): + def _removeLayer(self, name: str, **kwargs: Any) -> None: layerName = name glyphName = self.name font = self.font @@ -257,13 +286,18 @@ def _removeLayer(self, name, **kwargs): # Image # ----- - def _get_image(self): + def _get_image(self) -> Optional[RImage]: image = self.naked().image if image is None: return None return self.imageClass(image) - def _addImage(self, data, transformation=None, color=None): + def _addImage( + self, + data: bytes, + transformation: Optional[SextupleCollectionType[IntFloatType]] = None, + color: Optional[QuadrupleCollectionType[IntFloatType]] = None, + ) -> None: image = self.naked().image image = self.imageClass(image) image.glyph = self @@ -271,7 +305,7 @@ def _addImage(self, data, transformation=None, color=None): image.transformation = transformation image.color = color - def _clearImage(self, **kwargs): + def _clearImage(self, **kwargs: Any) -> None: self.naked().image = None # ---- @@ -280,21 +314,23 @@ def _clearImage(self, **kwargs): # Mark - def _get_markColor(self): + def _get_markColor(self) -> Optional[QuadrupleType[float]]: value = self.naked().markColor if value is not None: value = tuple(value) return value - def _set_markColor(self, value): + def _set_markColor( + self, value: Optional[QuadrupleCollectionType[IntFloatType]] + ) -> None: self.naked().markColor = value # Note - def _get_note(self): + def _get_note(self) -> Optional[str]: return self.naked().note - def _set_note(self, value): + def _set_note(self, value: Optional[str]) -> None: self.naked().note = value # ----------- @@ -303,19 +339,19 @@ def _set_note(self, value): # lib - def _get_lib(self): - return self.libClass(wrap=self.naked().lib) + def _get_lib(self) -> RLib: + return self.libClass(pathOrObject=self.naked().lib) # tempLib - def _get_tempLib(self): - return self.libClass(wrap=self.naked().tempLib) + def _get_tempLib(self) -> RLib: + return self.libClass(pathOrObject=self.naked().tempLib) # --- # API # --- - def _loadFromGLIF(self, glifData, validate=True): + def _loadFromGLIF(self, glifData: str, validate: bool = True) -> None: try: readGlyphFromString( aString=glifData, @@ -323,10 +359,10 @@ def _loadFromGLIF(self, glifData, validate=True): pointPen=self.getPointPen(), validate=validate, ) - except GlifLibError: - raise FontPartsError("Not valid glif data") + except GlifLibError as e: + raise FontPartsError("Not valid glif data") from e - def _dumpToGLIF(self, glyphFormatVersion): + def _dumpToGLIF(self, glyphFormatVersion: int) -> str: glyph = self.naked() return writeGlyphToString( glyphName=glyph.name, diff --git a/Lib/fontParts/fontshell/groups.py b/Lib/fontParts/fontshell/groups.py index 66c86b2c..59e121c5 100644 --- a/Lib/fontParts/fontshell/groups.py +++ b/Lib/fontParts/fontshell/groups.py @@ -1,28 +1,45 @@ +from __future__ import annotations +from typing import Tuple, Dict, ItemsView + import defcon from fontParts.base import BaseGroups +from fontParts.base.annotations import CollectionType from fontParts.fontshell.base import RBaseObject +ValueType = Tuple[str, ...] +GroupsDict = Dict[str, ValueType] + class RGroups(RBaseObject, BaseGroups): wrapClass = defcon.Groups - def _get_side1KerningGroups(self): - return self.naked().getRepresentation("defcon.groups.kerningSide1Groups") + def _get_side1KerningGroups(self) -> GroupsDict: + groups = self.naked() + representation = groups.getRepresentation("defcon.groups.kerningSide1Groups") + return {k: tuple(v) for k, v in representation.items()} - def _get_side2KerningGroups(self): - return self.naked().getRepresentation("defcon.groups.kerningSide2Groups") + def _get_side2KerningGroups(self) -> GroupsDict: + groups = self.naked() + representation = groups.getRepresentation("defcon.groups.kerningSide2Groups") + return {k: tuple(v) for k, v in representation.items()} - def _items(self): - return self.naked().items() + def _items(self) -> ItemsView[str, Tuple[str]]: + groups = self.naked() + formatted = {k: tuple(v) for k, v in groups.items()} + return formatted.items() - def _contains(self, key): - return key in self.naked() + def _contains(self, key: str) -> bool: + groups = self.naked() + return key in groups - def _setItem(self, key, value): - self.naked()[key] = list(value) + def _setItem(self, key: str, value: CollectionType[str]) -> None: + groups = self.naked() + groups[key] = tuple(value) - def _getItem(self, key): - return self.naked()[key] + def _getItem(self, key: str) -> Tuple[str]: + groups = self.naked() + return tuple(groups[key]) - def _delItem(self, key): - del self.naked()[key] + def _delItem(self, key: str) -> None: + groups = self.naked() + del groups[key] diff --git a/Lib/fontParts/fontshell/guideline.py b/Lib/fontParts/fontshell/guideline.py index 57ba3aea..fe8387e5 100644 --- a/Lib/fontParts/fontshell/guideline.py +++ b/Lib/fontParts/fontshell/guideline.py @@ -1,18 +1,28 @@ +from __future__ import annotations +from typing import Optional + import defcon from fontParts.base import BaseGuideline +from fontParts.base.annotations import ( + QuadrupleType, + QuadrupleCollectionType, + IntFloatType, +) from fontParts.fontshell.base import RBaseObject class RGuideline(RBaseObject, BaseGuideline): wrapClass = defcon.Guideline - def _init(self, wrap=None): - if wrap is None: - wrap = self.wrapClass() - wrap.x = 0 - wrap.y = 0 - wrap.angle = 0 - super(RGuideline, self)._init(wrap=wrap) + def _init(self, pathOrObject: Optional[defcon.Guideline] = None) -> None: + if self.wrapClass is not None: + if pathOrObject is None: + pathOrObject = self.wrapClass() + if pathOrObject is not None: + pathOrObject.x = 0 + pathOrObject.y = 0 + pathOrObject.angle = 0 + super(RGuideline, self)._init(pathOrObject=pathOrObject) # -------- # Position @@ -20,26 +30,26 @@ def _init(self, wrap=None): # x - def _get_x(self): + def _get_x(self) -> float: return self.naked().x - def _set_x(self, value): + def _set_x(self, value: float) -> None: self.naked().x = value # y - def _get_y(self): + def _get_y(self) -> float: return self.naked().y - def _set_y(self, value): + def _set_y(self, value: float) -> None: self.naked().y = value # angle - def _get_angle(self): + def _get_angle(self) -> float: return self.naked().angle - def _set_angle(self, value): + def _set_angle(self, value: Optional[IntFloatType]) -> None: self.naked().angle = value # -------------- @@ -48,32 +58,32 @@ def _set_angle(self, value): # identifier - def _get_identifier(self): - guideline = self.naked() - return guideline.identifier + def _get_identifier(self) -> Optional[str]: + return self.naked().identifier - def _getIdentifier(self): - guideline = self.naked() - return guideline.generateIdentifier() + def _getIdentifier(self) -> str: + return self.naked().generateIdentifier() - def _setIdentifier(self, value): + def _setIdentifier(self, value: str) -> None: self.naked().identifier = value # name - def _get_name(self): + def _get_name(self) -> Optional[str]: return self.naked().name - def _set_name(self, value): + def _set_name(self, value: Optional[str]) -> None: self.naked().name = value # color - def _get_color(self): + def _get_color(self) -> Optional[QuadrupleType[float]]: value = self.naked().color if value is not None: value = tuple(value) return value - def _set_color(self, value): + def _set_color( + self, value: Optional[QuadrupleCollectionType[IntFloatType]] + ) -> None: self.naked().color = value diff --git a/Lib/fontParts/fontshell/image.py b/Lib/fontParts/fontshell/image.py index 4cc664e8..889be55e 100644 --- a/Lib/fontParts/fontshell/image.py +++ b/Lib/fontParts/fontshell/image.py @@ -1,12 +1,23 @@ +from __future__ import annotations +from typing import Optional + import defcon +from fontTools.ufoLib.validators import pngValidator from fontParts.base import BaseImage, FontPartsError +from fontParts.base.annotations import ( + QuadrupleType, + SextupleType, + QuadrupleCollectionType, + SextupleCollectionType, + IntFloatType, +) from fontParts.fontshell.base import RBaseObject class RImage(RBaseObject, BaseImage): wrapClass = defcon.Image - _orphanData = None - _orphanColor = None + _orphanData: Optional[bytes] = None + _orphanColor: Optional[QuadrupleCollectionType[IntFloatType]] = None # ---------- # Attributes @@ -14,23 +25,26 @@ class RImage(RBaseObject, BaseImage): # Transformation - def _get_transformation(self): + def _get_transformation(self) -> SextupleType[float]: return self.naked().transformation - def _set_transformation(self, value): + def _set_transformation(self, value: SextupleCollectionType[float]) -> None: self.naked().transformation = value # Color - def _get_color(self): - if self.font is None: - return self._orphanColor + def _get_color(self) -> Optional[QuadrupleType[float]]: + if self.font is None and self._orphanColor is not None: + r, g, b, a = self._orphanColor + return (r, g, b, a) value = self.naked().color if value is not None: value = tuple(value) return value - def _set_color(self, value): + def _set_color( + self, value: Optional[QuadrupleCollectionType[IntFloatType]] + ) -> None: if self.font is None: self._orphanColor = value else: @@ -38,7 +52,7 @@ def _set_color(self, value): # Data - def _get_data(self): + def _get_data(self) -> Optional[bytes]: if self.font is None: return self._orphanData image = self.naked() @@ -50,9 +64,7 @@ def _get_data(self): return None return images[fileName] - def _set_data(self, value): - from fontTools.ufoLib.validators import pngValidator - + def _set_data(self, value: bytes) -> None: if not isinstance(value, bytes): raise FontPartsError("The image data provided is not valid.") if not pngValidator(data=value)[0]: diff --git a/Lib/fontParts/fontshell/info.py b/Lib/fontParts/fontshell/info.py index fa988865..37f4f6ee 100644 --- a/Lib/fontParts/fontshell/info.py +++ b/Lib/fontParts/fontshell/info.py @@ -1,3 +1,6 @@ +from __future__ import annotations +from typing import Any + import defcon from fontParts.base import BaseInfo from fontParts.fontshell.base import RBaseObject @@ -6,8 +9,8 @@ class RInfo(RBaseObject, BaseInfo): wrapClass = defcon.Info - def _getAttr(self, attr): + def _getAttr(self, attr: str) -> Any: return getattr(self.naked(), attr) - def _setAttr(self, attr, value): + def _setAttr(self, attr: str, value: Any) -> None: setattr(self.naked(), attr, value) diff --git a/Lib/fontParts/fontshell/kerning.py b/Lib/fontParts/fontshell/kerning.py index 080b7c5e..9b0b36b8 100644 --- a/Lib/fontParts/fontshell/kerning.py +++ b/Lib/fontParts/fontshell/kerning.py @@ -1,4 +1,9 @@ +from __future__ import annotations +from typing import Any +from collections.abc import ItemsView + import defcon +from fontParts.base.annotations import PairCollectionType from fontParts.base import BaseKerning from fontParts.fontshell.base import RBaseObject @@ -6,20 +11,20 @@ class RKerning(RBaseObject, BaseKerning): wrapClass = defcon.Kerning - def _items(self): + def _items(self) -> ItemsView[str, int]: return self.naked().items() - def _contains(self, key): + def _contains(self, key: str) -> bool: return key in self.naked() - def _setItem(self, key, value): + def _setItem(self, key: str, value: int) -> None: self.naked()[key] = value - def _getItem(self, key): + def _getItem(self, key: str) -> Any: return self.naked()[key] - def _delItem(self, key): + def _delItem(self, key: str) -> None: del self.naked()[key] - def _find(self, pair, default=0): + def _find(self, pair: PairCollectionType[str], default: int = 0) -> int: return self.naked().find(pair, default) diff --git a/Lib/fontParts/fontshell/layer.py b/Lib/fontParts/fontshell/layer.py index 84162134..fd556ae9 100644 --- a/Lib/fontParts/fontshell/layer.py +++ b/Lib/fontParts/fontshell/layer.py @@ -1,9 +1,16 @@ +from __future__ import annotations +from typing import TYPE_CHECKING, Optional, Tuple, Dict, Any + import defcon from fontParts.base import BaseLayer +from fontParts.base.annotations import QuadrupleCollectionType, IntFloatType from fontParts.fontshell.base import RBaseObject from fontParts.fontshell.lib import RLib from fontParts.fontshell.glyph import RGlyph +if TYPE_CHECKING: + from fontParts.base.glyph import BaseGlyph + class RLayer(RBaseObject, BaseLayer): wrapClass = defcon.Layer @@ -16,13 +23,13 @@ class RLayer(RBaseObject, BaseLayer): # lib - def _get_lib(self): - return self.libClass(wrap=self.naked().lib) + def _get_lib(self) -> RLib: + return self.libClass(pathOrObject=self.naked().lib) # tempLib - def _get_tempLib(self): - return self.libClass(wrap=self.naked().tempLib) + def _get_tempLib(self) -> RLib: + return self.libClass(pathOrObject=self.naked().tempLib) # -------------- # Identification @@ -30,41 +37,43 @@ def _get_tempLib(self): # name - def _get_name(self): + def _get_name(self) -> str: return self.naked().name - def _set_name(self, value, **kwargs): + def _set_name(self, value: str, **kwargs: Any) -> None: self.naked().name = value # color - def _get_color(self): + def _get_color(self) -> Optional[QuadrupleCollectionType[IntFloatType]]: value = self.naked().color if value is not None: value = tuple(value) return value - def _set_color(self, value, **kwargs): + def _set_color( + self, value: Optional[QuadrupleCollectionType[IntFloatType]], **kwargs: Any + ) -> None: self.naked().color = value # ----------------- # Glyph Interaction # ----------------- - def _getItem(self, name, **kwargs): + def _getItem(self, name: str, **kwargs: Any) -> RGlyph: layer = self.naked() glyph = layer[name] return self.glyphClass(glyph) - def _keys(self, **kwargs): - return self.naked().keys() + def _keys(self, **kwargs: Any) -> Tuple[str, ...]: + return tuple(self.naked().keys()) - def _newGlyph(self, name, **kwargs): + def _newGlyph(self, name: str, **kwargs: Any) -> BaseGlyph: layer = self.naked() layer.newGlyph(name) return self[name] - def _removeGlyph(self, name, **kwargs): + def _removeGlyph(self, name: str, **kwargs: Any) -> None: layer = self.naked() del layer[name] @@ -72,10 +81,10 @@ def _removeGlyph(self, name, **kwargs): # mapping # ------- - def _getReverseComponentMapping(self): + def _getReverseComponentMapping(self) -> Dict[str, Tuple[str, ...]]: mapping = self.naked().componentReferences return {k: tuple(v) for k, v in mapping.items()} - def _getCharacterMapping(self): + def _getCharacterMapping(self) -> Dict[int, Tuple[str, ...]]: mapping = self.naked().unicodeData return {k: tuple(v) for k, v in mapping.items()} diff --git a/Lib/fontParts/fontshell/lib.py b/Lib/fontParts/fontshell/lib.py index dadf870a..31cd453a 100644 --- a/Lib/fontParts/fontshell/lib.py +++ b/Lib/fontParts/fontshell/lib.py @@ -1,22 +1,28 @@ +from __future__ import annotations +from typing import TYPE_CHECKING, Any + import defcon from fontParts.base import BaseLib from fontParts.fontshell.base import RBaseObject +if TYPE_CHECKING: + from collections.abc import ItemsView + class RLib(RBaseObject, BaseLib): wrapClass = defcon.Lib - def _items(self): + def _items(self) -> ItemsView[str, Any]: return self.naked().items() - def _contains(self, key): + def _contains(self, key: str) -> bool: return key in self.naked() - def _setItem(self, key, value): + def _setItem(self, key: str, value: Any) -> None: self.naked()[key] = value - def _getItem(self, key): + def _getItem(self, key: str) -> Any: return self.naked()[key] - def _delItem(self, key): + def _delItem(self, key: str) -> None: del self.naked()[key] diff --git a/Lib/fontParts/fontshell/point.py b/Lib/fontParts/fontshell/point.py index 14cbba5f..cfec069d 100644 --- a/Lib/fontParts/fontshell/point.py +++ b/Lib/fontParts/fontshell/point.py @@ -1,4 +1,9 @@ +from __future__ import annotations +from typing import Optional + import defcon + +from fontParts.base.annotations import IntFloatType from fontParts.base import BasePoint, FontPartsError from fontParts.fontshell.base import RBaseObject @@ -6,19 +11,19 @@ class RPoint(RBaseObject, BasePoint): wrapClass = defcon.Point - def _init(self, wrap=None): - if wrap is None: - wrap = self.wrapClass((0, 0)) - super(RPoint, self)._init(wrap=wrap) + def _init(self, pathOrObject: Optional[defcon.Point] = None) -> None: + if pathOrObject is None and self.wrapClass is not None: + pathOrObject = self.wrapClass((0, 0)) + super(RPoint, self)._init(pathOrObject=pathOrObject) - def _postChangeNotification(self): + def _postChangeNotification(self) -> None: contour = self.contour if contour is None: return contour.naked().postNotification("Contour.PointsChanged") self.changed() - def changed(self): + def changed(self) -> None: self.contour.naked().dirty = True # ---------- @@ -27,42 +32,40 @@ def changed(self): # type - def _get_type(self): + def _get_type(self) -> str: value = self.naked().segmentType if value is None: value = "offcurve" return value - def _set_type(self, value): - if value == "offcurve": - value = None - self.naked().segmentType = value + def _set_type(self, value: str) -> None: + self.naked().segmentType = None if value == "offcurve" else value self._postChangeNotification() # smooth - def _get_smooth(self): + def _get_smooth(self) -> bool: return self.naked().smooth - def _set_smooth(self, value): + def _set_smooth(self, value: bool) -> None: self.naked().smooth = value self._postChangeNotification() # x - def _get_x(self): + def _get_x(self) -> IntFloatType: return self.naked().x - def _set_x(self, value): + def _set_x(self, value: IntFloatType) -> None: self.naked().x = value self._postChangeNotification() # y - def _get_y(self): + def _get_y(self) -> IntFloatType: return self.naked().y - def _set_y(self, value): + def _set_y(self, value: IntFloatType) -> None: self.naked().y = value self._postChangeNotification() @@ -72,20 +75,19 @@ def _set_y(self, value): # name - def _get_name(self): + def _get_name(self) -> Optional[str]: return self.naked().name - def _set_name(self, value): + def _set_name(self, value: str) -> None: self.naked().name = value self._postChangeNotification() # identifier - def _get_identifier(self): - point = self.naked() - return point.identifier + def _get_identifier(self) -> Optional[str]: + return self.naked().identifier - def _getIdentifier(self): + def _getIdentifier(self) -> str: point = self.naked() value = point.identifier if value is not None: diff --git a/Lib/fontParts/test/test_font.py b/Lib/fontParts/test/test_font.py index c677c82f..1e20915f 100644 --- a/Lib/fontParts/test/test_font.py +++ b/Lib/fontParts/test/test_font.py @@ -470,7 +470,7 @@ def testCases(path): def test_copy(self): font = self.getFont_glyphs() copy = font.copy() - self.assertEqual(font.keys(), copy.keys()) + self.assertCountEqual(font.keys(), copy.keys()) font = self.getFont_glyphs() font.defaultLayer.name = "hello" diff --git a/Lib/fontParts/test/test_groups.py b/Lib/fontParts/test/test_groups.py index 31f9818b..cd2a3123 100644 --- a/Lib/fontParts/test/test_groups.py +++ b/Lib/fontParts/test/test_groups.py @@ -7,10 +7,10 @@ def getGroups_generic(self): groups, _ = self.objectGenerator("groups") groups.update( { - "group 1": ["A", "B", "C"], - "group 2": ["x", "y", "z"], - "group 3": [], - "group 4": ["A"], + "group 1": ("A", "B", "C"), + "group 2": ("x", "y", "z"), + "group 3": (), + "group 4": ("A",), } ) return groups @@ -147,10 +147,10 @@ def test_get_not_found(self): def getGroups_kerning(self): groups = self.getGroups_generic() kerningGroups = { - "public.kern1.A": ["A", "Aacute"], - "public.kern1.O": ["O", "D"], - "public.kern2.A": ["A", "Aacute"], - "public.kern2.O": ["O", "C"], + "public.kern1.A": ("A", "Aacute"), + "public.kern1.O": ("O", "D"), + "public.kern2.A": ("A", "Aacute"), + "public.kern2.O": ("O", "C"), } groups.update(kerningGroups) return groups @@ -163,7 +163,7 @@ def test_side1KerningGroups(self): def test_get_side1KerningGroups(self): groups = self.getGroups_kerning() - expected = {"public.kern1.A": ["A", "Aacute"], "public.kern1.O": ["O", "D"]} + expected = {"public.kern1.A": ("A", "Aacute"), "public.kern1.O": ("O", "D")} self.assertEqual(groups._get_side1KerningGroups(), expected) def test_side2KerningGroups(self): @@ -173,7 +173,7 @@ def test_side2KerningGroups(self): def test_get_side2KerningGroups(self): groups = self.getGroups_kerning() - expected = {"public.kern1.A": ["A", "Aacute"], "public.kern1.O": ["O", "D"]} + expected = {"public.kern1.A": ("A", "Aacute"), "public.kern1.O": ("O", "D")} self.assertEqual(groups._get_side1KerningGroups(), expected) # ----