From 72621e14cbad19d8471d39a9d4815dd4236fb773 Mon Sep 17 00:00:00 2001 From: knutnergaard Date: Sat, 1 Mar 2025 22:46:49 +0100 Subject: [PATCH 1/8] Add type annotation and resolve `mypy` errors. --- Lib/fontParts/world.py | 179 ++++++++++++++++++++++++++++------------- 1 file changed, 123 insertions(+), 56 deletions(-) diff --git a/Lib/fontParts/world.py b/Lib/fontParts/world.py index b1e2782d..8f409e1f 100644 --- a/Lib/fontParts/world.py +++ b/Lib/fontParts/world.py @@ -1,8 +1,48 @@ +# pylint: disable=C0103, C0114 +from __future__ import annotations import os import glob - - -def OpenFonts(directory=None, showInterface=True, fileExtensions=None): +from typing import ( + TYPE_CHECKING, Callable, Dict, Iterable, Optional, Tuple, Union +) +from collections.abc import Generator +from types import FunctionType + +from fontParts.base.annotations import T, CollectionType + +if TYPE_CHECKING: + from fontParts.base.font import BaseFont + from fontParts.base.glyph import BaseGlyph + from fontParts.base.layer import BaseLayer + from fontParts.base.contour import BaseContour + from fontParts.base.segment import BaseSegment + from fontParts.base.point import BasePoint + from fontParts.base.component import BaseComponent + from fontParts.base.anchor import BaseAnchor + from fontParts.base.guideline import BaseGuideline + +SortOptionType = Union[str, Callable, CollectionType[Union[str, Callable]]] +BaseTypes = Union[ + "BaseFont", + "BaseGlyph", + "BaseLayer", + "BaseContour", + "BaseSegment", + "BasePoint", + "BaseComponent", + "BaseAnchor", + "BaseGuideline", + "BaseFontList" +] +RegistryType = Dict[str, Optional[Callable[[], BaseTypes]]] +InfoType = Union[str, int, float, bool] + + +def OpenFonts( + directory: Optional[Union[str, CollectionType[str]]] = None, + showInterface: bool = True, + fileExtensions: Optional[CollectionType[str]] = None +) -> Generator[BaseFont]: """ Open all fonts with the given **fileExtensions** located in **directory**. If **directory** is ``None``, a dialog for @@ -26,17 +66,20 @@ def OpenFonts(directory=None, showInterface=True, fileExtensions=None): """ from fontParts.ui import GetFileOrFolder + directories: CollectionType[str] if fileExtensions is None: - fileExtensions = dispatcher["OpenFontsFileExtensions"] - if isinstance(directory, str): + fileExtensions = dispatcher["OpenFontsFileExtensions"]() + if directory is None: + directory = GetFileOrFolder(allowsMultipleSelection=True) + elif isinstance(directory, str): directories = [directory] - elif directory is None: - directories = GetFileOrFolder(allowsMultipleSelection=True) else: directories = directory if directories: globPatterns = [] for directory in directories: + if not fileExtensions: + continue if os.path.splitext(directory)[-1] in fileExtensions: globPatterns.append(directory) elif not os.path.isdir(directory): @@ -51,7 +94,7 @@ def OpenFonts(directory=None, showInterface=True, fileExtensions=None): yield OpenFont(path, showInterface=showInterface) -def OpenFont(path, showInterface=True): +def OpenFont(path: str, showInterface: bool = True) -> BaseFont: """ Open font located at **path**. If **showInterface** is ``False``, the font should be opened without @@ -68,7 +111,10 @@ def OpenFont(path, showInterface=True): return dispatcher["OpenFont"](pathOrObject=path, showInterface=showInterface) -def NewFont(familyName=None, styleName=None, showInterface=True): +def NewFont( + familyName: Optional[str] = None, + styleName: Optional[str] = None, + showInterface: bool = True) -> BaseFont: """ Create a new font. **familyName** will be assigned to ``font.info.familyName`` and **styleName** @@ -91,14 +137,14 @@ def NewFont(familyName=None, styleName=None, showInterface=True): ) -def CurrentFont(): +def CurrentFont() -> BaseFont: """ Get the "current" font. """ return dispatcher["CurrentFont"]() -def CurrentGlyph(): +def CurrentGlyph() -> BaseGlyph: """ Get the "current" glyph from :func:`CurrentFont`. @@ -111,7 +157,7 @@ def CurrentGlyph(): return dispatcher["CurrentGlyph"]() -def CurrentLayer(): +def CurrentLayer() -> BaseLayer: """ Get the "current" layer from :func:`CurrentGlyph`. @@ -124,7 +170,7 @@ def CurrentLayer(): return dispatcher["CurrentLayer"]() -def CurrentContours(): +def CurrentContours() -> Tuple[BaseContour, ...]: """ Get the "currently" selected contours from :func:`CurrentGlyph`. @@ -139,14 +185,14 @@ def CurrentContours(): return dispatcher["CurrentContours"]() -def _defaultCurrentContours(): +def _defaultCurrentContours() -> Tuple[BaseContour, ...]: glyph = CurrentGlyph() if glyph is None: return () return glyph.selectedContours -def CurrentSegments(): +def CurrentSegments() -> Tuple[BaseSegment, ...]: """ Get the "currently" selected segments from :func:`CurrentContours`. @@ -161,7 +207,7 @@ def CurrentSegments(): return dispatcher["CurrentSegments"]() -def _defaultCurrentSegments(): +def _defaultCurrentSegments() -> Tuple[BaseSegment, ...]: glyph = CurrentGlyph() if glyph is None: return () @@ -171,7 +217,7 @@ def _defaultCurrentSegments(): return tuple(segments) -def CurrentPoints(): +def CurrentPoints() -> Tuple[BasePoint, ...]: """ Get the "currently" selected points from :func:`CurrentContours`. @@ -186,7 +232,7 @@ def CurrentPoints(): return dispatcher["CurrentPoints"]() -def _defaultCurrentPoints(): +def _defaultCurrentPoints() -> Tuple[BasePoint, ...]: glyph = CurrentGlyph() if glyph is None: return () @@ -196,7 +242,7 @@ def _defaultCurrentPoints(): return tuple(points) -def CurrentComponents(): +def CurrentComponents() -> Tuple[BaseComponent, ...]: """ Get the "currently" selected components from :func:`CurrentGlyph`. @@ -211,14 +257,14 @@ def CurrentComponents(): return dispatcher["CurrentComponents"]() -def _defaultCurrentComponents(): +def _defaultCurrentComponents() -> Tuple[BaseComponent, ...]: glyph = CurrentGlyph() if glyph is None: return () return glyph.selectedComponents -def CurrentAnchors(): +def CurrentAnchors() -> Tuple[BaseAnchor, ...]: """ Get the "currently" selected anchors from :func:`CurrentGlyph`. @@ -233,14 +279,14 @@ def CurrentAnchors(): return dispatcher["CurrentAnchors"]() -def _defaultCurrentAnchors(): +def _defaultCurrentAnchors() -> Tuple[BaseAnchor, ...]: glyph = CurrentGlyph() if glyph is None: return () return glyph.selectedAnchors -def CurrentGuidelines(): +def CurrentGuidelines() -> Tuple[BaseGuideline, ...]: """ Get the "currently" selected guidelines from :func:`CurrentGlyph`. This will include both font level and glyph level guidelines. @@ -256,7 +302,7 @@ def CurrentGuidelines(): return dispatcher["CurrentGuidelines"]() -def _defaultCurrentGuidelines(): +def _defaultCurrentGuidelines() -> Tuple[BaseGuideline, ...]: guidelines = [] font = CurrentFont() if font is not None: @@ -267,7 +313,7 @@ def _defaultCurrentGuidelines(): return tuple(guidelines) -def AllFonts(sortOptions=None): +def AllFonts(sortOptions: Optional[CollectionType[str]] = None) -> BaseFontList: """ Get a list of all open fonts. Optionally, provide a value for ``sortOptions`` to sort the fonts. See @@ -295,11 +341,11 @@ def AllFonts(sortOptions=None): return fontList -def RFont(path=None, showInterface=True): +def RFont(path: Optional[str] = None, showInterface: bool = True) -> fontshell.RFont: return dispatcher["RFont"](pathOrObject=path, showInterface=showInterface) -def RGlyph(): +def RGlyph() -> fontshell.RGlyph: return dispatcher["RGlyph"]() @@ -308,7 +354,7 @@ def RGlyph(): # --------- -def FontList(fonts=None): +def FontList(fonts: Optional[Iterable[T]] = None): """ Get a list with font specific methods. @@ -329,7 +375,7 @@ def FontList(fonts=None): class BaseFontList(list): # Sort - def sortBy(self, sortOptions, reverse=False): + def sortBy(self, sortOptions: SortOptionType, reverse: bool = False) -> None: """ Sort ``fonts`` with the ordering preferences defined by ``sortBy``. ``sortBy`` must be one of the following: @@ -418,7 +464,6 @@ def sortBy(self, sortOptions, reverse=False): >>> fonts.sortBy("magic") """ - from types import FunctionType valueGetters = dict( familyName=_sortValue_familyName, @@ -433,7 +478,7 @@ def sortBy(self, sortOptions, reverse=False): if isinstance(sortOptions, str) or isinstance(sortOptions, FunctionType): sortOptions = [sortOptions] if not isinstance(sortOptions, (list, tuple)): - raise ValueError("sortOptions must a string, list or function.") + raise ValueError("sortOptions must be a string, list or function.") if not sortOptions: raise ValueError("At least one sort option must be defined.") if sortOptions == ["magic"]: @@ -449,12 +494,14 @@ def sortBy(self, sortOptions, reverse=False): for originalIndex, font in enumerate(self): sortable = [] for valueName in sortOptions: + value = None if isinstance(valueName, FunctionType): value = valueName(font) - elif valueName in valueGetters: - value = valueGetters[valueName](font) - elif hasattr(font.info, valueName): - value = getattr(font.info, valueName) + elif isinstance(valueName, str): + if valueName in valueGetters: + value = valueGetters[valueName](font) + elif hasattr(font.info, valueName): + value = getattr(font.info, valueName) else: raise ValueError(f"Unknown sort option: {repr(valueName)}") sortable.append(value) @@ -470,7 +517,10 @@ def sortBy(self, sortOptions, reverse=False): # Search - def getFontsByFontInfoAttribute(self, *attributeValuePairs): + def getFontsByFontInfoAttribute( + self, + *attributeValuePairs: Tuple[str, InfoType] + ) -> BaseFontList: """ Get a list of fonts that match the (attribute, value) combinations in ``attributeValuePairs``. @@ -487,7 +537,11 @@ def getFontsByFontInfoAttribute(self, *attributeValuePairs): found = self._matchFontInfoAttributes(found, (attr, value)) return found - def _matchFontInfoAttributes(self, fonts, attributeValuePair): + def _matchFontInfoAttributes( + self, + fonts: BaseFontList, + attributeValuePair: Tuple[str, InfoType] + ) -> BaseFontList: found = self.__class__() attr, value = attributeValuePair for font in fonts: @@ -495,21 +549,25 @@ def _matchFontInfoAttributes(self, fonts, attributeValuePair): found.append(font) return found - def getFontsByFamilyName(self, familyName): + def getFontsByFamilyName(self, familyName: str) -> BaseFontList: """ Get a list of fonts that match ``familyName``. This will return an instance of :class:`BaseFontList`. """ return self.getFontsByFontInfoAttribute(("familyName", familyName)) - def getFontsByStyleName(self, styleName): + def getFontsByStyleName(self, styleName: str) -> BaseFontList: """ Get a list of fonts that match ``styleName``. This will return an instance of :class:`BaseFontList`. """ return self.getFontsByFontInfoAttribute(("styleName", styleName)) - def getFontsByFamilyNameStyleName(self, familyName, styleName): + def getFontsByFamilyNameStyleName( + self, + familyName: str, + styleName: str + ) -> BaseFontList: """ Get a list of fonts that match ``familyName`` and ``styleName``. This will return an instance of :class:`BaseFontList`. @@ -519,7 +577,7 @@ def getFontsByFamilyNameStyleName(self, familyName, styleName): ) -def _sortValue_familyName(font): +def _sortValue_familyName(font: BaseFont) -> str: """ Returns font.info.familyName. """ @@ -529,7 +587,7 @@ def _sortValue_familyName(font): return value -def _sortValue_styleName(font): +def _sortValue_styleName(font: BaseFont) -> str: """ Returns font.info.styleName. """ @@ -539,7 +597,7 @@ def _sortValue_styleName(font): return value -def _sortValue_isRoman(font): +def _sortValue_isRoman(font: BaseFont) -> int: """ Returns 0 if the font is roman. Returns 1 if the font is not roman. @@ -550,7 +608,7 @@ def _sortValue_isRoman(font): return 1 -def _sortValue_isItalic(font): +def _sortValue_isItalic(font: BaseFont) -> int: """ Returns 0 if the font is italic. Returns 1 if the font is not italic. @@ -564,7 +622,7 @@ def _sortValue_isItalic(font): return 1 -def _sortValue_widthValue(font): +def _sortValue_widthValue(font: BaseFont) -> int: """ Returns font.info.openTypeOS2WidthClass. """ @@ -574,7 +632,7 @@ def _sortValue_widthValue(font): return value -def _sortValue_weightValue(font): +def _sortValue_weightValue(font: BaseFont) -> int: """ Returns font.info.openTypeOS2WeightClass. """ @@ -584,7 +642,7 @@ def _sortValue_weightValue(font): return value -def _sortValue_isProportional(font): +def _sortValue_isProportional(font: BaseFont) -> int: """ Returns 0 if the font is proportional. Returns 1 if the font is not proportional. @@ -595,7 +653,7 @@ def _sortValue_isProportional(font): return 1 -def _sortValue_isMonospace(font): +def _sortValue_isMonospace(font: BaseFont) -> int: """ Returns 0 if the font is monospace. Returns 1 if the font is not monospace. @@ -619,14 +677,15 @@ def _sortValue_isMonospace(font): # ---------- -class _EnvironmentDispatcher(object): - def __init__(self, registryItems): - self._registry = {item: None for item in registryItems} +class _EnvironmentDispatcher: - def __setitem__(self, name, func): + def __init__(self, registryItems: CollectionType[str]) -> None: + self._registry: RegistryType = {item: None for item in registryItems} + + def __setitem__(self, name: str, func: Optional[Callable]) -> None: self._registry[name] = func - def __getitem__(self, name): + def __getitem__(self, name: str) -> Callable: func = self._registry[name] if func is None: raise NotImplementedError @@ -664,6 +723,8 @@ def __getitem__(self, name): "RKerning", "RLib", ] + + ) # Register the default functions. @@ -685,11 +746,13 @@ def __getitem__(self, name): # OpenFonts - dispatcher["OpenFontsFileExtensions"] = [".ufo"] + dispatcher["OpenFontsFileExtensions"] = lambda: [".ufo"] # OpenFont, RFont - def _fontshellRFont(pathOrObject=None, showInterface=True): + def _fontshellRFont( + pathOrObject: Optional[Union[str, BaseFont]] = None, + showInterface: bool = True) -> fontshell.RFont: return fontshell.RFont(pathOrObject=pathOrObject, showInterface=showInterface) dispatcher["OpenFont"] = _fontshellRFont @@ -697,7 +760,11 @@ def _fontshellRFont(pathOrObject=None, showInterface=True): # NewFont - def _fontshellNewFont(familyName=None, styleName=None, showInterface=True): + def _fontshellNewFont( + familyName: Optional[str] = None, + styleName: Optional[str] = None, + showInterface: bool = True + ) -> fontshell.RFont: font = fontshell.RFont(showInterface=showInterface) if familyName is not None: font.info.familyName = familyName From af59fac20e8cfb3ac53c57a6befec8e0dd104f52 Mon Sep 17 00:00:00 2001 From: knutnergaard <15194233+knutnergaard@users.noreply.github.com> Date: Sat, 1 Mar 2025 21:48:30 +0000 Subject: [PATCH 2/8] Format fixes by ruff --- Lib/fontParts/world.py | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/Lib/fontParts/world.py b/Lib/fontParts/world.py index 8f409e1f..1ae47172 100644 --- a/Lib/fontParts/world.py +++ b/Lib/fontParts/world.py @@ -2,9 +2,7 @@ from __future__ import annotations import os import glob -from typing import ( - TYPE_CHECKING, Callable, Dict, Iterable, Optional, Tuple, Union -) +from typing import TYPE_CHECKING, Callable, Dict, Iterable, Optional, Tuple, Union from collections.abc import Generator from types import FunctionType @@ -32,7 +30,7 @@ "BaseComponent", "BaseAnchor", "BaseGuideline", - "BaseFontList" + "BaseFontList", ] RegistryType = Dict[str, Optional[Callable[[], BaseTypes]]] InfoType = Union[str, int, float, bool] @@ -40,8 +38,8 @@ def OpenFonts( directory: Optional[Union[str, CollectionType[str]]] = None, - showInterface: bool = True, - fileExtensions: Optional[CollectionType[str]] = None + showInterface: bool = True, + fileExtensions: Optional[CollectionType[str]] = None, ) -> Generator[BaseFont]: """ Open all fonts with the given **fileExtensions** located in @@ -112,9 +110,10 @@ def OpenFont(path: str, showInterface: bool = True) -> BaseFont: def NewFont( - familyName: Optional[str] = None, - styleName: Optional[str] = None, - showInterface: bool = True) -> BaseFont: + familyName: Optional[str] = None, + styleName: Optional[str] = None, + showInterface: bool = True, +) -> BaseFont: """ Create a new font. **familyName** will be assigned to ``font.info.familyName`` and **styleName** @@ -518,8 +517,7 @@ def sortBy(self, sortOptions: SortOptionType, reverse: bool = False) -> None: # Search def getFontsByFontInfoAttribute( - self, - *attributeValuePairs: Tuple[str, InfoType] + self, *attributeValuePairs: Tuple[str, InfoType] ) -> BaseFontList: """ Get a list of fonts that match the (attribute, value) @@ -538,9 +536,7 @@ def getFontsByFontInfoAttribute( return found def _matchFontInfoAttributes( - self, - fonts: BaseFontList, - attributeValuePair: Tuple[str, InfoType] + self, fonts: BaseFontList, attributeValuePair: Tuple[str, InfoType] ) -> BaseFontList: found = self.__class__() attr, value = attributeValuePair @@ -564,9 +560,7 @@ def getFontsByStyleName(self, styleName: str) -> BaseFontList: return self.getFontsByFontInfoAttribute(("styleName", styleName)) def getFontsByFamilyNameStyleName( - self, - familyName: str, - styleName: str + self, familyName: str, styleName: str ) -> BaseFontList: """ Get a list of fonts that match ``familyName`` and ``styleName``. @@ -678,7 +672,6 @@ def _sortValue_isMonospace(font: BaseFont) -> int: class _EnvironmentDispatcher: - def __init__(self, registryItems: CollectionType[str]) -> None: self._registry: RegistryType = {item: None for item in registryItems} @@ -723,8 +716,6 @@ def __getitem__(self, name: str) -> Callable: "RKerning", "RLib", ] - - ) # Register the default functions. @@ -751,8 +742,8 @@ def __getitem__(self, name: str) -> Callable: # OpenFont, RFont def _fontshellRFont( - pathOrObject: Optional[Union[str, BaseFont]] = None, - showInterface: bool = True) -> fontshell.RFont: + pathOrObject: Optional[Union[str, BaseFont]] = None, showInterface: bool = True + ) -> fontshell.RFont: return fontshell.RFont(pathOrObject=pathOrObject, showInterface=showInterface) dispatcher["OpenFont"] = _fontshellRFont @@ -761,9 +752,9 @@ def _fontshellRFont( # NewFont def _fontshellNewFont( - familyName: Optional[str] = None, - styleName: Optional[str] = None, - showInterface: bool = True + familyName: Optional[str] = None, + styleName: Optional[str] = None, + showInterface: bool = True, ) -> fontshell.RFont: font = fontshell.RFont(showInterface=showInterface) if familyName is not None: From 1336c70dafd52abd8608c6f1b93bf6606c9fb154 Mon Sep 17 00:00:00 2001 From: knutnergaard Date: Sun, 2 Mar 2025 23:25:07 +0100 Subject: [PATCH 3/8] Add/immprove documentation. --- Lib/fontParts/world.py | 336 ++++++++++++++++++++++++----------------- 1 file changed, 198 insertions(+), 138 deletions(-) diff --git a/Lib/fontParts/world.py b/Lib/fontParts/world.py index 1ae47172..eae4322c 100644 --- a/Lib/fontParts/world.py +++ b/Lib/fontParts/world.py @@ -41,26 +41,30 @@ def OpenFonts( showInterface: bool = True, fileExtensions: Optional[CollectionType[str]] = None, ) -> Generator[BaseFont]: - """ - Open all fonts with the given **fileExtensions** located in - **directory**. If **directory** is ``None``, a dialog for - selecting a directory will be opened. **directory** may also - be a list of directories. If **showInterface** is ``False``, - the font should be opened without graphical interface. The default - for **showInterface** is ``True``. + """Open all fonts located in the specified directories. - The fonts are located within the directory using the `glob` - `_ module. The - patterns are created with ``os.path.join(glob, "*" + fileExtension)`` - for every file extension in ``fileExtensions``. If ``fileExtensions`` - if ``None`` the environment will use its default fileExtensions. + The fonts are located within the directory using the :mod:`glob` module. + The patterns are created with ``os.path.join(directory, "*" + fileExtension)`` + for every file extension in `fileExtensions`. - :: + :param directory: The optional directory :class:`str` or the :class:`list` + or :class:`tuple` of directories to search for fonts. If :obj:`None` (default), + a dialog for selecting a directory will be opened. + :param showInterface: A :class:`bool` indicating whether to show the graphical + interface. If :obj:`False`, the font should be opened without a graphical + interface. Defaults to :obj:`True`. + :param fileExtensions: The optional file extensions to search for as a :class:`list` + or :class:`tuple` of :class:`str` items. If :obj:`None` (default), the default + file extensions will be used. + :return: A :class:`generator` yielding the opened fonts. - from fontParts.world import * + Example:: + + from fontParts.world import OpenFonts fonts = OpenFonts() fonts = OpenFonts(showInterface=False) + """ from fontParts.ui import GetFileOrFolder @@ -93,18 +97,21 @@ def OpenFonts( def OpenFont(path: str, showInterface: bool = True) -> BaseFont: - """ - Open font located at **path**. If **showInterface** - is ``False``, the font should be opened without - graphical interface. The default for **showInterface** - is ``True``. + """Open font located at the specified path. - :: + :param path: The path to the font file to be opened as a :class:`str` + :param showInterface: A :class:`bool` indicating whether to show the graphical + interface. If :obj:`False`, the font should be opened without a graphical + interface. Defaults to :obj:`True`. + :return: The newly opened :class:`BaseFont` instance. - from fontParts.world import * + Example:: + + from fontParts.world import OpenFont font = OpenFont("/path/to/my/font.ufo") font = OpenFont("/path/to/my/font.ufo", showInterface=False) + """ return dispatcher["OpenFont"](pathOrObject=path, showInterface=showInterface) @@ -114,22 +121,25 @@ def NewFont( styleName: Optional[str] = None, showInterface: bool = True, ) -> BaseFont: - """ - Create a new font. **familyName** will be assigned - to ``font.info.familyName`` and **styleName** - will be assigned to ``font.info.styleName``. These - are optional and default to ``None``. If **showInterface** - is ``False``, the font should be created without - graphical interface. The default for **showInterface** - is ``True``. + """Create a new font. + + :param familyName: The optional :attr:`BaseInfo.familyName` to apply to the font as + a :class:`str`. + :param styleName: The optional :attr:`BaseInfo.styleName` to apply to the font as + a :class:`str`. + :param showInterface: A :class:`bool` indicating whether to show the graphical + interface. If :obj:`False`, the font should be opened without a graphical + interface. Defaults to :obj:`True`. + :return: The newly created :class:`BaseFont` instance. - :: + Example:: from fontParts.world import * font = NewFont() font = NewFont(familyName="My Family", styleName="My Style") font = NewFont(showInterface=False) + """ return dispatcher["NewFont"]( familyName=familyName, styleName=styleName, showInterface=showInterface @@ -137,17 +147,22 @@ def NewFont( def CurrentFont() -> BaseFont: - """ - Get the "current" font. + """Get the currently active font. + + :return: A :class:`BaseFont` subclass instance representing the currently active + font. + """ return dispatcher["CurrentFont"]() def CurrentGlyph() -> BaseGlyph: - """ - Get the "current" glyph from :func:`CurrentFont`. + """Get the currently active glyph from :func:`CurrentFont`. - :: + :return: A :class:`BaseGlyph` subclass instance representing the currently active + glyph. + + Example:: from fontParts.world import * @@ -157,29 +172,33 @@ def CurrentGlyph() -> BaseGlyph: def CurrentLayer() -> BaseLayer: - """ - Get the "current" layer from :func:`CurrentGlyph`. + """Get the currently active layer from :func:`CurrentGlyph`. - :: + :return: A :class:`BaseLayer` subclass instance representing the currently active + glyph layer. + + Example:: from fontParts.world import * layer = CurrentLayer() + """ return dispatcher["CurrentLayer"]() def CurrentContours() -> Tuple[BaseContour, ...]: - """ - Get the "currently" selected contours from :func:`CurrentGlyph`. + """Get the currently selected contours from :func:`CurrentGlyph`. + + :return: A :class:`tuple` of :class:`BaseContour` subclass instances representing + the currently selected glyph contours. - :: + Example:: from fontParts.world import * contours = CurrentContours() - This returns an immutable list, even when nothing is selected. """ return dispatcher["CurrentContours"]() @@ -192,16 +211,17 @@ def _defaultCurrentContours() -> Tuple[BaseContour, ...]: def CurrentSegments() -> Tuple[BaseSegment, ...]: - """ - Get the "currently" selected segments from :func:`CurrentContours`. + """Get the currently selected segments from :func:`CurrentContours`. + + :return: A :class:`tuple` of :class:`BaseSegments` subclass instances representing + the currently selected contour segments. - :: + Example:: from fontParts.world import * segments = CurrentSegments() - This returns an immutable list, even when nothing is selected. """ return dispatcher["CurrentSegments"]() @@ -217,16 +237,17 @@ def _defaultCurrentSegments() -> Tuple[BaseSegment, ...]: def CurrentPoints() -> Tuple[BasePoint, ...]: - """ - Get the "currently" selected points from :func:`CurrentContours`. + """Get the currently selected points from :func:`CurrentContours`. - :: + :return: A :class:`tuple` of :class:`BasePoint` subclass instances representing + the currently selected contour points. + + Example:: from fontParts.world import * points = CurrentPoints() - This returns an immutable list, even when nothing is selected. """ return dispatcher["CurrentPoints"]() @@ -242,10 +263,12 @@ def _defaultCurrentPoints() -> Tuple[BasePoint, ...]: def CurrentComponents() -> Tuple[BaseComponent, ...]: - """ - Get the "currently" selected components from :func:`CurrentGlyph`. + """Get the currently selected components from :func:`CurrentGlyph`. + + :return: A :class:`tuple` of :class:`BaseComponent` subclass instances representing + the currently selected glyph components. - :: + Example:: from fontParts.world import * @@ -264,16 +287,17 @@ def _defaultCurrentComponents() -> Tuple[BaseComponent, ...]: def CurrentAnchors() -> Tuple[BaseAnchor, ...]: - """ - Get the "currently" selected anchors from :func:`CurrentGlyph`. + """Get the currently selected anchors from :func:`CurrentGlyph`. - :: + :return: A :class:`tuple` of :class:`BaseAnchor` subclass instances representing + the currently selected glyph anchors. + + Example:: from fontParts.world import * anchors = CurrentAnchors() - This returns an immutable list, even when nothing is selected. """ return dispatcher["CurrentAnchors"]() @@ -286,17 +310,19 @@ def _defaultCurrentAnchors() -> Tuple[BaseAnchor, ...]: def CurrentGuidelines() -> Tuple[BaseGuideline, ...]: - """ - Get the "currently" selected guidelines from :func:`CurrentGlyph`. + """Get the currently selected guidelines from :func:`CurrentGlyph`. + This will include both font level and glyph level guidelines. - :: + :return: A :class:`tuple` of :class:`BaseGuideline` subclass instances representing + the currently selected guidelines. + + Example:: from fontParts.world import * guidelines = CurrentGuidelines() - This returns an immutable list, even when nothing is selected. """ return dispatcher["CurrentGuidelines"]() @@ -313,12 +339,16 @@ def _defaultCurrentGuidelines() -> Tuple[BaseGuideline, ...]: def AllFonts(sortOptions: Optional[CollectionType[str]] = None) -> BaseFontList: - """ - Get a list of all open fonts. Optionally, provide a - value for ``sortOptions`` to sort the fonts. See - :meth:`world.FontList.sortBy` for options. + """Get a list of all open fonts. + + Optionally, provide a value for `sortOptions` to sort the fonts. See + :meth:`BaseFontList.sortBy` for options. + + :param sortOptions: The optional :class:`list` or :class:`tuple` of :class:`str` + sort options to apply to the list. Defaults to :obj:`None`. + :return: A :class:`BaseFontList` instance representing all open fonts. - :: + Example:: from fontParts.world import * @@ -333,6 +363,7 @@ def AllFonts(sortOptions: Optional[CollectionType[str]] = None) -> BaseFontList: fonts = AllFonts(["familyName", "styleName"]) for font in fonts: # do something + """ fontList = FontList(dispatcher["AllFonts"]()) if sortOptions is not None: @@ -354,10 +385,11 @@ def RGlyph() -> fontshell.RGlyph: def FontList(fonts: Optional[Iterable[T]] = None): - """ - Get a list with font specific methods. + """Get a list with font-specific methods. - :: + :return: A :class:`BaseFontList` instance. + + Example:: from fontParts.world import * @@ -372,98 +404,109 @@ def FontList(fonts: Optional[Iterable[T]] = None): class BaseFontList(list): + """Represent a :class:`list` with font-specific methods.""" + # Sort def sortBy(self, sortOptions: SortOptionType, reverse: bool = False) -> None: - """ - Sort ``fonts`` with the ordering preferences defined - by ``sortBy``. ``sortBy`` must be one of the following: + """Sort items according to specified ordering preferences. + + Sorting preferences may be defined as follows: - * sort description string - * :class:`BaseInfo` attribute name - * sort value function - * list/tuple containing sort description strings, :class:`BaseInfo` - attribute names and/or sort value functions - * ``"magic"`` + - A :ref:`sort description ` as a :class:`str` + - A :ref:`font info attribute name` ` + - A :class:`list` or :class:`tuple` containing a mix of any of the above + - The special keyword ``"magic"`` (see :ref:`magic-sorting`) - Sort Description Strings - ------------------------ + .. _sort-descriptions: - The sort description strings, and how they modify the sort, are: + Sort Descriptions + ----------------- + + The following string-based sort descriptions determine sorting behavior: +----------------------+--------------------------------------+ - | ``"familyName"`` | Family names by alphabetical order. | + | Sort Description | Effect | + +======================+======================================+ + | ``"familyName"`` | Sort by family name (A-Z). | +----------------------+--------------------------------------+ - | ``"styleName"`` | Style names by alphabetical order. | + | ``"styleName"`` | Sort by style name (A-Z). | +----------------------+--------------------------------------+ - | ``"isItalic"`` | Italics before romans. | + | ``"isItalic"`` | Sort italics before romans. | +----------------------+--------------------------------------+ - | ``"isRoman"`` | Romans before italics. | + | ``"isRoman"`` | Sort romans before italics. | +----------------------+--------------------------------------+ - | ``"widthValue"`` | Width values by numerical order. | + | ``"widthValue"`` | Sort by width value (low-high). | +----------------------+--------------------------------------+ - | ``"weightValue"`` | Weight values by numerical order. | + | ``"weightValue"`` | Sort by weight value (low-high). | +----------------------+--------------------------------------+ - | ``"monospace"`` | Monospaced before proportional. | + | ``"monospace"`` | Sort monospaced before proportional. | +----------------------+--------------------------------------+ - | ``"isProportional"`` | Proportional before monospaced. | + | ``"isProportional"`` | Sort proportional before monospaced. | +----------------------+--------------------------------------+ - :: - - >>> fonts.sortBy(("familyName", "styleName")) - + .. _info-attributes: Font Info Attribute Names ------------------------- - Any :class:`BaseFont` attribute name may be included as - a sort option. For example, to sort by x-height value, - you'd use the ``"xHeight"`` attribute name. - - :: - - >>> fonts.sortBy("xHeight") + Any attribute of :class:`BaseInfo` may be used as a sorting criterion. + For example, sorting by x-height value can be achieved using the + attribute name ``"xHeight"``. + .. _sort-value-function: Sort Value Function ------------------- - A sort value function must be a function that accepts - one argument, ``font``. This function must return - a sortable value for the given font. For example: + A sort value function is a :class:`Callable` that takes a single + argument, `font`, and returns a sortable value. Example:: - :: + def glyph_count_sort(font): + return len(font) + + fonts.sortBy(glyph_count_sort) - >>> def glyphCountSortValue(font): - >>> return len(font) - >>> - >>> fonts.sortBy(glyphCountSortValue) + A :class:`list` or :class:`tuple` of sort descriptions and/or sort functions + may be provided to specify sorting precedence, from most to least important. - A list of sort description strings and/or sort functions - may also be provided. This should be in order of most - to least important. For example, to sort by family name - and then style name, do this: + .. _magic-sorting: + Magic Sorting + ------------- - "magic" - ------- + If ``"magic"`` is specified, fonts are sorted using the following + sequence of criteria: - If "magic" is given for ``sortBy``, the fonts will be - sorted based on this sort description sequence: + #. ``"familyName"`` + #. ``"isProportional"`` + #. ``"widthValue"`` + #. ``"weightValue"`` + #. ``"styleName"`` + #. ``"isRoman"`` - * ``"familyName"`` - * ``"isProportional"`` - * ``"widthValue"`` - * ``"weightValue"`` - * ``"styleName"`` - * ``"isRoman"`` + Parameters + ---------- + + :param sortOptions: The sorting criteria, given as a single :class:`str`, + :class:`Callable`, or a :class:`list` or :class:`tuple` of these elements. + :param reverse: Whether to reverse the sort order. Defaults to :obj:`False`. + + Examples + -------- :: - >>> fonts.sortBy("magic") - """ + from fontParts.world import AllFonts + fonts = AllFonts() + fonts.sortBy("familyName") + fonts.sortBy(["familyName", "styleName"]) + fonts.sortBy("magic") + fonts.sortBy(lambda font: len(font)) + + """ valueGetters = dict( familyName=_sortValue_familyName, styleName=_sortValue_styleName, @@ -519,16 +562,22 @@ def sortBy(self, sortOptions: SortOptionType, reverse: bool = False) -> None: def getFontsByFontInfoAttribute( self, *attributeValuePairs: Tuple[str, InfoType] ) -> BaseFontList: - """ - Get a list of fonts that match the (attribute, value) - combinations in ``attributeValuePairs``. + r"""Get a list of fonts that match the specified attribute-value pairs. - :: + This method filters fonts based on one or more ``(attribute, value)`` pairs. + When multiple pairs are provided, only fonts that satisfy all conditions are + included. + + :param \*attributeValuePairs: The attribute-value pairs to search + for as :class:`tuple` instances, each containing a font attribute name + as a :class:`str` and the expected value. + :return: A :class:`BaseFontList` instance containing the matching fonts. + + Example:: >>> subFonts = fonts.getFontsByFontInfoAttribute(("xHeight", 20)) >>> subFonts = fonts.getFontsByFontInfoAttribute(("xHeight", 20), ("descender", -150)) - This will return an instance of :class:`BaseFontList`. """ found = self for attr, value in attributeValuePairs: @@ -546,25 +595,36 @@ def _matchFontInfoAttributes( return found def getFontsByFamilyName(self, familyName: str) -> BaseFontList: - """ - Get a list of fonts that match ``familyName``. - This will return an instance of :class:`BaseFontList`. + """Get a list of fonts that match the provided family name. + + :param familyName: The :attr:`BaseInfo.familyName` to search for as + a :class:`str`. + :return: A :class:`BaseFontList` instance containing the matching fonts. + """ return self.getFontsByFontInfoAttribute(("familyName", familyName)) def getFontsByStyleName(self, styleName: str) -> BaseFontList: - """ - Get a list of fonts that match ``styleName``. - This will return an instance of :class:`BaseFontList`. + """Get a list of fonts that match the provided style name. + + :param styleName: The :attr:`BaseInfo.styleName` to search for as + a :class:`str`. + :return: A :class:`BaseFontList` instance containing the matching fonts. + """ return self.getFontsByFontInfoAttribute(("styleName", styleName)) def getFontsByFamilyNameStyleName( self, familyName: str, styleName: str ) -> BaseFontList: - """ - Get a list of fonts that match ``familyName`` and ``styleName``. - This will return an instance of :class:`BaseFontList`. + """Get a list of fonts that match the provided family name and style name. + + :param familyName: The :attr:`BaseInfo.familyName` to search for as + a :class:`str`. + :param styleName: The :attr:`BaseInfo.styleName` to search for as + a :class:`str`. + :return: A :class:`BaseFontList` instance containing the matching fonts. + """ return self.getFontsByFontInfoAttribute( ("familyName", familyName), ("styleName", styleName) From 372800cbac2fd21abff8d9fbdd93660ba1f1ff5d Mon Sep 17 00:00:00 2001 From: knutnergaard <15194233+knutnergaard@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:25:51 +0000 Subject: [PATCH 4/8] Format fixes by ruff --- Lib/fontParts/world.py | 59 +++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/Lib/fontParts/world.py b/Lib/fontParts/world.py index eae4322c..bb062b8c 100644 --- a/Lib/fontParts/world.py +++ b/Lib/fontParts/world.py @@ -44,17 +44,17 @@ def OpenFonts( """Open all fonts located in the specified directories. The fonts are located within the directory using the :mod:`glob` module. - The patterns are created with ``os.path.join(directory, "*" + fileExtension)`` + The patterns are created with ``os.path.join(directory, "*" + fileExtension)`` for every file extension in `fileExtensions`. - :param directory: The optional directory :class:`str` or the :class:`list` - or :class:`tuple` of directories to search for fonts. If :obj:`None` (default), + :param directory: The optional directory :class:`str` or the :class:`list` + or :class:`tuple` of directories to search for fonts. If :obj:`None` (default), a dialog for selecting a directory will be opened. - :param showInterface: A :class:`bool` indicating whether to show the graphical - interface. If :obj:`False`, the font should be opened without a graphical + :param showInterface: A :class:`bool` indicating whether to show the graphical + interface. If :obj:`False`, the font should be opened without a graphical interface. Defaults to :obj:`True`. - :param fileExtensions: The optional file extensions to search for as a :class:`list` - or :class:`tuple` of :class:`str` items. If :obj:`None` (default), the default + :param fileExtensions: The optional file extensions to search for as a :class:`list` + or :class:`tuple` of :class:`str` items. If :obj:`None` (default), the default file extensions will be used. :return: A :class:`generator` yielding the opened fonts. @@ -100,8 +100,8 @@ def OpenFont(path: str, showInterface: bool = True) -> BaseFont: """Open font located at the specified path. :param path: The path to the font file to be opened as a :class:`str` - :param showInterface: A :class:`bool` indicating whether to show the graphical - interface. If :obj:`False`, the font should be opened without a graphical + :param showInterface: A :class:`bool` indicating whether to show the graphical + interface. If :obj:`False`, the font should be opened without a graphical interface. Defaults to :obj:`True`. :return: The newly opened :class:`BaseFont` instance. @@ -121,14 +121,14 @@ def NewFont( styleName: Optional[str] = None, showInterface: bool = True, ) -> BaseFont: - """Create a new font. + """Create a new font. - :param familyName: The optional :attr:`BaseInfo.familyName` to apply to the font as + :param familyName: The optional :attr:`BaseInfo.familyName` to apply to the font as a :class:`str`. - :param styleName: The optional :attr:`BaseInfo.styleName` to apply to the font as + :param styleName: The optional :attr:`BaseInfo.styleName` to apply to the font as a :class:`str`. - :param showInterface: A :class:`bool` indicating whether to show the graphical - interface. If :obj:`False`, the font should be opened without a graphical + :param showInterface: A :class:`bool` indicating whether to show the graphical + interface. If :obj:`False`, the font should be opened without a graphical interface. Defaults to :obj:`True`. :return: The newly created :class:`BaseFont` instance. @@ -149,7 +149,7 @@ def NewFont( def CurrentFont() -> BaseFont: """Get the currently active font. - :return: A :class:`BaseFont` subclass instance representing the currently active + :return: A :class:`BaseFont` subclass instance representing the currently active font. """ @@ -190,7 +190,7 @@ def CurrentLayer() -> BaseLayer: def CurrentContours() -> Tuple[BaseContour, ...]: """Get the currently selected contours from :func:`CurrentGlyph`. - :return: A :class:`tuple` of :class:`BaseContour` subclass instances representing + :return: A :class:`tuple` of :class:`BaseContour` subclass instances representing the currently selected glyph contours. Example:: @@ -213,7 +213,7 @@ def _defaultCurrentContours() -> Tuple[BaseContour, ...]: def CurrentSegments() -> Tuple[BaseSegment, ...]: """Get the currently selected segments from :func:`CurrentContours`. - :return: A :class:`tuple` of :class:`BaseSegments` subclass instances representing + :return: A :class:`tuple` of :class:`BaseSegments` subclass instances representing the currently selected contour segments. Example:: @@ -239,7 +239,7 @@ def _defaultCurrentSegments() -> Tuple[BaseSegment, ...]: def CurrentPoints() -> Tuple[BasePoint, ...]: """Get the currently selected points from :func:`CurrentContours`. - :return: A :class:`tuple` of :class:`BasePoint` subclass instances representing + :return: A :class:`tuple` of :class:`BasePoint` subclass instances representing the currently selected contour points. Example:: @@ -265,7 +265,7 @@ def _defaultCurrentPoints() -> Tuple[BasePoint, ...]: def CurrentComponents() -> Tuple[BaseComponent, ...]: """Get the currently selected components from :func:`CurrentGlyph`. - :return: A :class:`tuple` of :class:`BaseComponent` subclass instances representing + :return: A :class:`tuple` of :class:`BaseComponent` subclass instances representing the currently selected glyph components. Example:: @@ -289,7 +289,7 @@ def _defaultCurrentComponents() -> Tuple[BaseComponent, ...]: def CurrentAnchors() -> Tuple[BaseAnchor, ...]: """Get the currently selected anchors from :func:`CurrentGlyph`. - :return: A :class:`tuple` of :class:`BaseAnchor` subclass instances representing + :return: A :class:`tuple` of :class:`BaseAnchor` subclass instances representing the currently selected glyph anchors. Example:: @@ -314,7 +314,7 @@ def CurrentGuidelines() -> Tuple[BaseGuideline, ...]: This will include both font level and glyph level guidelines. - :return: A :class:`tuple` of :class:`BaseGuideline` subclass instances representing + :return: A :class:`tuple` of :class:`BaseGuideline` subclass instances representing the currently selected guidelines. Example:: @@ -339,12 +339,12 @@ def _defaultCurrentGuidelines() -> Tuple[BaseGuideline, ...]: def AllFonts(sortOptions: Optional[CollectionType[str]] = None) -> BaseFontList: - """Get a list of all open fonts. + """Get a list of all open fonts. Optionally, provide a value for `sortOptions` to sort the fonts. See :meth:`BaseFontList.sortBy` for options. - :param sortOptions: The optional :class:`list` or :class:`tuple` of :class:`str` + :param sortOptions: The optional :class:`list` or :class:`tuple` of :class:`str` sort options to apply to the list. Defaults to :obj:`None`. :return: A :class:`BaseFontList` instance representing all open fonts. @@ -466,6 +466,7 @@ def sortBy(self, sortOptions: SortOptionType, reverse: bool = False) -> None: def glyph_count_sort(font): return len(font) + fonts.sortBy(glyph_count_sort) A :class:`list` or :class:`tuple` of sort descriptions and/or sort functions @@ -565,11 +566,11 @@ def getFontsByFontInfoAttribute( r"""Get a list of fonts that match the specified attribute-value pairs. This method filters fonts based on one or more ``(attribute, value)`` pairs. - When multiple pairs are provided, only fonts that satisfy all conditions are + When multiple pairs are provided, only fonts that satisfy all conditions are included. :param \*attributeValuePairs: The attribute-value pairs to search - for as :class:`tuple` instances, each containing a font attribute name + for as :class:`tuple` instances, each containing a font attribute name as a :class:`str` and the expected value. :return: A :class:`BaseFontList` instance containing the matching fonts. @@ -597,7 +598,7 @@ def _matchFontInfoAttributes( def getFontsByFamilyName(self, familyName: str) -> BaseFontList: """Get a list of fonts that match the provided family name. - :param familyName: The :attr:`BaseInfo.familyName` to search for as + :param familyName: The :attr:`BaseInfo.familyName` to search for as a :class:`str`. :return: A :class:`BaseFontList` instance containing the matching fonts. @@ -607,7 +608,7 @@ def getFontsByFamilyName(self, familyName: str) -> BaseFontList: def getFontsByStyleName(self, styleName: str) -> BaseFontList: """Get a list of fonts that match the provided style name. - :param styleName: The :attr:`BaseInfo.styleName` to search for as + :param styleName: The :attr:`BaseInfo.styleName` to search for as a :class:`str`. :return: A :class:`BaseFontList` instance containing the matching fonts. @@ -619,9 +620,9 @@ def getFontsByFamilyNameStyleName( ) -> BaseFontList: """Get a list of fonts that match the provided family name and style name. - :param familyName: The :attr:`BaseInfo.familyName` to search for as + :param familyName: The :attr:`BaseInfo.familyName` to search for as a :class:`str`. - :param styleName: The :attr:`BaseInfo.styleName` to search for as + :param styleName: The :attr:`BaseInfo.styleName` to search for as a :class:`str`. :return: A :class:`BaseFontList` instance containing the matching fonts. From be51542a41a63b68e551f02eb499404793c60d58 Mon Sep 17 00:00:00 2001 From: knutnergaard Date: Mon, 3 Mar 2025 14:31:48 +0100 Subject: [PATCH 5/8] Revise `BaseFontList.sortBy`. - change wrong type exception for `sortOptions` to `ValueError`` - add exceptions to docs - Remove superflous headings --- Lib/fontParts/world.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Lib/fontParts/world.py b/Lib/fontParts/world.py index eae4322c..2510d862 100644 --- a/Lib/fontParts/world.py +++ b/Lib/fontParts/world.py @@ -409,9 +409,9 @@ class BaseFontList(list): # Sort def sortBy(self, sortOptions: SortOptionType, reverse: bool = False) -> None: - """Sort items according to specified ordering preferences. + """Sort items according to specified options. - Sorting preferences may be defined as follows: + Sorting options may be defined as follows: - A :ref:`sort description ` as a :class:`str` - A :ref:`font info attribute name` None: - A :class:`list` or :class:`tuple` containing a mix of any of the above - The special keyword ``"magic"`` (see :ref:`magic-sorting`) + .. _sort-descriptions: Sort Descriptions @@ -446,6 +447,7 @@ def sortBy(self, sortOptions: SortOptionType, reverse: bool = False) -> None: | ``"isProportional"`` | Sort proportional before monospaced. | +----------------------+--------------------------------------+ + .. _info-attributes: Font Info Attribute Names @@ -455,6 +457,7 @@ def sortBy(self, sortOptions: SortOptionType, reverse: bool = False) -> None: For example, sorting by x-height value can be achieved using the attribute name ``"xHeight"``. + .. _sort-value-function: Sort Value Function @@ -471,6 +474,7 @@ def glyph_count_sort(font): A :class:`list` or :class:`tuple` of sort descriptions and/or sort functions may be provided to specify sorting precedence, from most to least important. + .. _magic-sorting: Magic Sorting @@ -486,17 +490,17 @@ def glyph_count_sort(font): #. ``"styleName"`` #. ``"isRoman"`` - Parameters - ---------- - :param sortOptions: The sorting criteria, given as a single :class:`str`, - :class:`Callable`, or a :class:`list` or :class:`tuple` of these elements. + :param sortOptions: The sorting option(s), given as a single :class:`str`, + :class:`FunctionType`, or a :class:`list` or :class:`tuple` of several. :param reverse: Whether to reverse the sort order. Defaults to :obj:`False`. + :raises TypeError: If `sortOptions` is not a :class:`str`, + :class:`FunctionType`, :class:`list` or :class:`tuple`. + :raises ValueError: + - If `sortOptions` does not conatain any sorting options. + - If `sortOptions` contains an unrecognized value or value item. - Examples - -------- - - :: + Example:: from fontParts.world import AllFonts @@ -520,7 +524,7 @@ def glyph_count_sort(font): if isinstance(sortOptions, str) or isinstance(sortOptions, FunctionType): sortOptions = [sortOptions] if not isinstance(sortOptions, (list, tuple)): - raise ValueError("sortOptions must be a string, list or function.") + raise TypeError("sortOptions must be a string, list or function.") if not sortOptions: raise ValueError("At least one sort option must be defined.") if sortOptions == ["magic"]: From c810e68cbf21d8e14bc474b6548772952a6b7bf6 Mon Sep 17 00:00:00 2001 From: knutnergaard <15194233+knutnergaard@users.noreply.github.com> Date: Mon, 3 Mar 2025 13:41:21 +0000 Subject: [PATCH 6/8] Format fixes by ruff --- Lib/fontParts/world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/fontParts/world.py b/Lib/fontParts/world.py index d6f87712..4c0c37fd 100644 --- a/Lib/fontParts/world.py +++ b/Lib/fontParts/world.py @@ -493,9 +493,9 @@ def glyph_count_sort(font): :param sortOptions: The sorting option(s), given as a single :class:`str`, - :class:`FunctionType`, or a :class:`list` or :class:`tuple` of several. + :class:`FunctionType`, or a :class:`list` or :class:`tuple` of several. :param reverse: Whether to reverse the sort order. Defaults to :obj:`False`. - :raises TypeError: If `sortOptions` is not a :class:`str`, + :raises TypeError: If `sortOptions` is not a :class:`str`, :class:`FunctionType`, :class:`list` or :class:`tuple`. :raises ValueError: - If `sortOptions` does not conatain any sorting options. From efbc262b921bbc5e71b08c8a52d4688b5cf6e79e Mon Sep 17 00:00:00 2001 From: knutnergaard Date: Mon, 3 Mar 2025 14:45:50 +0100 Subject: [PATCH 7/8] Change `SortOptionType` from `Callable` to `FunctionType`. --- Lib/fontParts/world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/fontParts/world.py b/Lib/fontParts/world.py index 4c0c37fd..68491b01 100644 --- a/Lib/fontParts/world.py +++ b/Lib/fontParts/world.py @@ -19,7 +19,7 @@ from fontParts.base.anchor import BaseAnchor from fontParts.base.guideline import BaseGuideline -SortOptionType = Union[str, Callable, CollectionType[Union[str, Callable]]] +SortOptionType = Union[str, FunctionType, CollectionType[Union[str, Callable]]] BaseTypes = Union[ "BaseFont", "BaseGlyph", From d821a763d5872c9e89aec10edb513c8c9783e365 Mon Sep 17 00:00:00 2001 From: knutnergaard Date: Mon, 3 Mar 2025 14:45:50 +0100 Subject: [PATCH 8/8] Change `SortOptionType` from `Callable` to `FunctionType`. --- Lib/fontParts/world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/fontParts/world.py b/Lib/fontParts/world.py index 4c0c37fd..6c0c6674 100644 --- a/Lib/fontParts/world.py +++ b/Lib/fontParts/world.py @@ -19,7 +19,7 @@ from fontParts.base.anchor import BaseAnchor from fontParts.base.guideline import BaseGuideline -SortOptionType = Union[str, Callable, CollectionType[Union[str, Callable]]] +SortOptionType = Union[str, FunctionType, CollectionType[Union[str, FunctionType]]] BaseTypes = Union[ "BaseFont", "BaseGlyph",