From bcf1da5f653efa462ed13fd6365af3ba054c7642 Mon Sep 17 00:00:00 2001 From: Knut Nergaard Date: Mon, 18 Nov 2024 20:25:57 +0100 Subject: [PATCH 1/3] Corrected annotation (#776) * Solve mypy errors. * Format fixes by ruff * Remove guideline from appenGuideline doctoring --------- Co-authored-by: knutnergaard Co-authored-by: Ben Kiel --- Lib/fontParts/base/font.py | 63 ++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/Lib/fontParts/base/font.py b/Lib/fontParts/base/font.py index ebba679f..3762eaea 100644 --- a/Lib/fontParts/base/font.py +++ b/Lib/fontParts/base/font.py @@ -3,6 +3,7 @@ import os from typing import TYPE_CHECKING, Any, Generic, List, Optional, Tuple, Type, Union +from fontTools import ufoLib from fontParts.base.errors import FontPartsError from fontParts.base.base import dynamicProperty, InterpolationMixin from fontParts.base.layer import _BaseGlyphVendor @@ -12,6 +13,7 @@ from fontParts.base.annotations import ( CharacterMappingType, CollectionType, + IntFloatType, QuadrupleCollectionType, PairCollectionType, TransformationType, @@ -1566,7 +1568,7 @@ def __setitem__(self, name: str, glyph: BaseGlyph) -> BaseGlyph: """, ) - def _get_base_glyphOrder(self) -> Tuple[str]: + def _get_base_glyphOrder(self) -> Tuple[str, ...]: value = self._get_glyphOrder() value = normalizers.normalizeGlyphOrder(value) return value @@ -1575,7 +1577,7 @@ def _set_base_glyphOrder(self, value: CollectionType[str]) -> None: value = normalizers.normalizeGlyphOrder(value) self._set_glyphOrder(value) - def _get_glyphOrder(self) -> Tuple[str]: + def _get_glyphOrder(self) -> Tuple[str, ...]: r"""Get the order of the glyphs in the native font. This is the environment implementation of the @@ -1745,10 +1747,10 @@ def _lenGuidelines(self, **kwargs: Any) -> int: self.raiseNotImplementedError() def _getitem__guidelines(self, index: int) -> BaseGuideline: - index = normalizers.normalizeIndex(index) - if index >= self._len__guidelines(): - raise ValueError(f"No guideline located at index {index}.") - guideline = self._getGuideline(index) + normalizedIndex = normalizers.normalizeIndex(index) + if normalizedIndex is None or normalizedIndex >= self._len__guidelines(): + raise ValueError(f"No guideline located at index {normalizedIndex}.") + guideline = self._getGuideline(normalizedIndex) self._setFontInGuideline(guideline) return guideline @@ -1778,7 +1780,7 @@ def _getGuidelineIndex(self, guideline: BaseGuideline) -> int: def appendGuideline( self, position: Optional[PairCollectionType[IntFloatType]] = None, - angle: Optional[float] = None, + angle: Optional[IntFloatType] = None, name: Optional[str] = None, color: Optional[QuadrupleCollectionType[IntFloatType]] = None, guideline: Optional[BaseGuideline] = None, @@ -1829,8 +1831,10 @@ def appendGuideline( ) if normalizedGuideline.identifier not in existing: identifier = normalizedGuideline.identifier - position = normalizers.normalizeCoordinateTuple(position) - angle = normalizers.normalizeRotationAngle(angle) + if position is not None: + position = normalizers.normalizeCoordinateTuple(position) + if angle is not None: + angle = normalizers.normalizeRotationAngle(angle) if name is not None: name = normalizers.normalizeGuidelineName(name) if color is not None: @@ -1848,7 +1852,6 @@ def _appendGuideline( angle: Optional[float], name: Optional[str], color: Optional[QuadrupleCollectionType[IntFloatType]], - guideline: Optional[BaseGuideline], **kwargs, ) -> BaseGuideline: r"""Append a new guideline to the native font. @@ -1861,9 +1864,6 @@ def _appendGuideline( :param angle: The angle for the guideline as a :class:`float`. :param name: The name for the guideline as a :class:`str`. :param color: The color for the guideline as a :ref:`type-color`. - :param guideline: The :class:`BaseGuideline` subclass instance from - which to copy values. If `position`, `angle`, `name`, or `color` - are specified, those values will be used instead. :param \**kwargs: Additional keyword arguments. :return: The newly appended instance of the :class:`BaseGuideline` subclass. @@ -1892,10 +1892,13 @@ def removeGuideline(self, guideline: Union[int, BaseGuideline]) -> None: index = guideline else: index = self._getGuidelineIndex(guideline) - index = normalizers.normalizeIndex(index) - if index >= self._len__guidelines(): - raise ValueError(f"No guideline located at index {index}.") - self._removeGuideline(index) + normalizedIndex = normalizers.normalizeIndex(index) + # Avoid mypy conflict with normalizeIndex -> Optional[int] + if normalizedIndex is None: + return + if normalizedIndex >= self._len__guidelines(): + raise ValueError(f"No guideline located at index {normalizedIndex}.") + self._removeGuideline(normalizedIndex) def _removeGuideline(self, index: int, **kwargs: Any) -> None: """Remove the guideline at the specified index. @@ -2366,8 +2369,8 @@ def _set_selectedLayerNames(self, value: List[str]) -> None: "base_selectedGuidelines", """Get or set the selected guidelines in the font. - :param value: The :class:`list` of :class:`BaseGuideline` instances - to select. + :param value: The :class:`list` of either :class:`BaseGuideline` instances + to select or their corresponding indexes. :return: A :class:`tuple` of currently selected :class:`BaseGuideline` instances. @@ -2411,17 +2414,25 @@ def _get_selectedGuidelines(self) -> Tuple[BaseGuideline, ...]: """ return self._getSelectedSubObjects(self.guidelines) - def _set_base_selectedGuidelines(self, value: List[BaseGuideline]) -> None: + def _set_base_selectedGuidelines( + self, value: List[Union[BaseGuideline, int]] + ) -> None: normalized = [] - for i in value: - if isinstance(i, int): - i = normalizers.normalizeIndex(i) + for guideline in value: + normalizedGuideline: Union[BaseGuideline, int] + if isinstance(guideline, int): + normalizedIndex = normalizers.normalizeIndex(guideline) + # Avoid mypy conflict with normalizeIndex -> Optional[int] + if normalizedIndex is None: + continue + normalizedGuideline = normalizedIndex else: - i = normalizers.normalizeGuideline(i) - normalized.append(i) + normalizedGuideline = normalizers.normalizeGuideline(guideline) + + normalized.append(normalizedGuideline) self._set_selectedGuidelines(normalized) - def _set_selectedGuidelines(self, value: List[BaseGuideline]) -> None: + def _set_selectedGuidelines(self, value: List[Union[BaseGuideline, int]]) -> None: """Set the selected guidelines in the native font. This is the environment implementation of From f67a487ea713291a7cbdf4c3809b67b3507294bb Mon Sep 17 00:00:00 2001 From: Ben Kiel Date: Mon, 18 Nov 2024 13:36:55 -0600 Subject: [PATCH 2/3] Stop testing 3.9, start testing 3.12 and 3.13 --- .github/workflows/run-tests.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 860cede6..65fdf7c1 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -22,17 +22,21 @@ jobs: if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')" strategy: matrix: - python-version: ['3.8', '3.9', '3.10', '3.11'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] platform: [ubuntu-latest, macos-latest, windows-latest] exclude: # Only test on the oldest and latest supported stable Python on macOS and Windows. - - platform: macos-latest - python-version: 3.9 - - platform: windows-latest - python-version: 3.9 - platform: macos-latest python-version: 3.10 - platform: windows-latest python-version: 3.10 + - platform: macos-latest + python-version: 3.11 + - platform: windows-latest + python-version: 3.11 + - platform: macos-latest + python-version: 3.13 + - platform: windows-latest + python-version: 3.13 steps: - uses: actions/checkout@v3.5.3 - name: Set up Python ${{ matrix.python-version }} From 8dd7eb21104d55faf5a39402976f8278088159e4 Mon Sep 17 00:00:00 2001 From: Ben Kiel Date: Mon, 18 Nov 2024 13:45:32 -0600 Subject: [PATCH 3/3] Drop 3.8 (#778) * Drop Python 3.8 * Update pyproject.toml * Update README.rst --- README.rst | 4 ++-- pyproject.toml | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 36bc18fd..9591760d 100644 --- a/README.rst +++ b/README.rst @@ -26,7 +26,7 @@ into something that you wish fontParts did/didn't do. Installation ~~~~~~~~~~~~ -FontParts requires `Python `__ 3.8 or later. +FontParts requires `Python `__ 3.9 or later. The package is listed in the Python Package Index (PyPI), so you can install it with `pip `__: @@ -123,7 +123,7 @@ or the ``TOXENV`` environment variable: :target: https://github.com/robotools/fontParts/actions?query=workflow%3ATests .. |PyPI| image:: https://img.shields.io/pypi/v/fontParts.svg :target: https://pypi.org/project/fontParts -.. |Versions| image:: https://img.shields.io/badge/python-3.8%2C%203.9%2C%203.10%2C%203.11-blue.svg +.. |Versions| image:: https://img.shields.io/badge/python-3.9%2C%203.10%2C%203.11%2C%203.12%2C%203.13-blue.svg :alt: Python Versions .. |Coverage| image:: https://codecov.io/gh/robotools/fontParts/branch/master/graph/badge.svg :target: https://codecov.io/gh/robotools/fontParts diff --git a/pyproject.toml b/pyproject.toml index abb4cb93..85c01fd3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ write_to = 'Lib/fontParts/_version.py' write_to_template = '__version__ = "{version}"' [tool.ruff] -target-version = "py38" +target-version = "py39" [tool.ruff.format] # Enable reformatting of code snippets in docstrings. diff --git a/setup.py b/setup.py index e557733a..ce55b5bf 100755 --- a/setup.py +++ b/setup.py @@ -46,7 +46,7 @@ "Topic :: Multimedia :: Graphics :: Graphics Conversion", "Topic :: Software Development :: Libraries", ], - python_requires=">=3.8", + python_requires=">=3.9", zip_safe=True, )