pax_global_header00006660000000000000000000000064151257136610014521gustar00rootroot0000000000000052 comment=dace2ca4ae9cbfb78775c02c93fd8bc2752948b1 statmake-2.0.1/000077500000000000000000000000001512571366100133325ustar00rootroot00000000000000statmake-2.0.1/.coveragerc000066400000000000000000000014141512571366100154530ustar00rootroot00000000000000[run] # measure 'branch' coverage in addition to 'statement' coverage # See: http://coverage.readthedocs.org/en/coverage-4.0.3/branch.html#branch branch = True parallel = True # list of directories or packages to measure source = statmake # these are treated as equivalent when combining data [paths] source = statmake */site-packages [report] # Regexes for lines to exclude from consideration exclude_lines = # keywords to use in inline comments to skip coverage pragma: no cover # don't complain if tests don't hit defensive assertion code raise AssertionError raise NotImplementedError # don't complain if non-runnable code isn't run if 0: if __name__ == .__main__.: # ignore source code that can’t be found ignore_errors = True statmake-2.0.1/.editorconfig000066400000000000000000000004061512571366100160070ustar00rootroot00000000000000# http://editorconfig.org root = true [*] indent_style = space indent_size = 4 trim_trailing_whitespace = true insert_final_newline = true charset = utf-8 end_of_line = lf [*.{yaml,yml,json,xml,designspace,stylespace,md}] indent_style = space indent_size = 2 statmake-2.0.1/.gitattributes000066400000000000000000000003251512571366100162250ustar00rootroot00000000000000# Set the default behavior, in case people don't have core.autocrlf set. * text=auto # Explicitly declare text files you want to always be normalized and converted # to native line endings on checkout. *.py text statmake-2.0.1/.github/000077500000000000000000000000001512571366100146725ustar00rootroot00000000000000statmake-2.0.1/.github/workflows/000077500000000000000000000000001512571366100167275ustar00rootroot00000000000000statmake-2.0.1/.github/workflows/ci.yml000066400000000000000000000030501512571366100200430ustar00rootroot00000000000000name: Continuous Integration on: push: branches: [master] tags: ["v*.*.*"] pull_request: branches: [master] jobs: test: runs-on: ${{ matrix.platform }} strategy: matrix: python-version: ["3.8", "3.13"] platform: [ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install the latest version of uv uses: astral-sh/setup-uv@v5 with: version: "latest" - name: Lint and test run: uvx --with tox-uv tox -e lint,py # https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/ deploy: # only run if the commit is tagged... if: startsWith(github.ref, 'refs/tags/v') # ... and the previous jobs completed successfully needs: - test runs-on: ubuntu-latest environment: name: publish-to-pypi url: https://pypi.org/p/statmake permissions: id-token: write # IMPORTANT: mandatory for trusted publishing steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.x" - name: Install the latest version of uv uses: astral-sh/setup-uv@v5 with: version: "latest" - name: Build and publish run: | uv build uv publish statmake-2.0.1/.gitignore000066400000000000000000000022661512571366100153300ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # dotenv .env # virtualenv .venv venv/ ENV/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ # VS Code .vscode .idea # Fontlab .vfb .bak statmake-2.0.1/LICENSE000066400000000000000000000020541512571366100143400ustar00rootroot00000000000000MIT License Copyright (c) 2019 Dalton Maag Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. statmake-2.0.1/README.md000066400000000000000000000077451512571366100146260ustar00rootroot00000000000000# statmake `statmake` takes a user-written Stylespace that defines [OpenType `STAT` information](https://docs.microsoft.com/en-us/typography/opentype/spec/stat) for an entire font family and then (potentially subsets and) applies it to a specific variable font. This spares users from having to deal with [raw TTX dumps](https://github.com/fonttools/fonttools/) and juggling with nameIDs. ## Installation The easiest way is by installing it with `pip`. You need at least Python 3.8. ``` pip3 install statmake ``` ## Usage ### External Stylespace file, stand-alone or referenced from a Designspace file If you are producing more than one variable font (i.e. you have multiple Designspace files), you can avoid duplicated information by writing a single all-encompassing Stylespace file which statmake will subset for each variable font. **Attention:** A `STAT` table is supposed to describe a font's relationship to the _entire_ family. If you have separate upright and italic variable fonts with a `wght` axis each, you need to mark each font's position on the `ital` axis _in the Designspace lib `org.statmake.additionalLocations` key_. The Designspace `` elements are not supposed to hold this information, so it must be done in a separate lib key. 1. Write a Stylespace file that describes each stop of all axes available in the entire family. See [tests/data/Test.stylespace](tests/data/Test.stylespace) for an annotated example. You can also use it as a starting point. 2. You can have the file stand-alone or use the Designspace lib's `org.statmake.stylespacePath` key to store the path to the Stylespace file relative to the Designspace file. See [tests/data/TestExternalStylespace.designspace](tests/data/TestExternalStylespace.designspace) for an example. 3. If you have one or more Designspace files which do not define all axes available to the family, you have to annotate them with the missing axis locations to get a complete `STAT` table. See the lib key at the bottom of [tests/data/Test_Wght_Upright.designspace](tests/data/Test_Wght_Upright.designspace) and [tests/data/Test_Wght_Italic.designspace](tests/data/Test_Wght_Italic.designspace) for an example. 4. Generate the variable font(s) as normal 5. If... 1. ... you store the Stylespace file stand-alone: run `statmake --designspace variable_font.designspace --stylespace your.stylespace variable_font.ttf`. 2. ... you store the Stylespace inline in the Designspace file or as a stand-alone file and added the relative path to it in the Designspace's `org.statmake.stylespacePath` key: run `statmake --designspace variable_font.designspace variable_font.ttf` Be sure to use the Designspace file that was used to generate the font to get the correct missing axis location definitions. ### Designspace file with inline Stylespace data If you are producing a single variable font containing an entire family, this approach will save you an external file. 1. Write the file as above, point 1. 2. Insert it into the Designspace file's lib under the `org.statmake.stylespace` key. See [tests/data/TestInlineStylespace.designspace](tests/data/TestInlineStylespace.designspace) for an example. 3. Proceed from point 3 above. ## Q: Can I please have something other than a .plist file? Yes, but you have to convert it to `.plist` yourself, as statmake currently only read `.plist` files. One possible converter is Adam Twardoch's [yaplon](https://pypi.org/project/yaplon/). ## Q: I'm getting errors about how statmake doesn't like the way I wrote the Stylespace, but I want the data to be that way? Use a custom script with the https://fonttools.readthedocs.io/en/latest/otlLib/builder.html#fontTools.otlLib.builder.buildStatTable API instead. ## Development setup The project uses `uv`; install it from https://docs.astral.sh/uv/, and then: ```bash # Install this project and its dependencies uv sync # Install tox globally for your user with uv support (if your other projects use it too) uv tool install tox --with tox-uv # Run tests on various Python versions tox ```statmake-2.0.1/pyproject.toml000066400000000000000000000036311512571366100162510ustar00rootroot00000000000000[build-system] build-backend = "hatchling.build" requires = ["hatchling", "hatch-vcs"] [project] name = "statmake" dynamic = ["version"] description = "Applies STAT information from a Stylespace to a variable font." readme = "README.md" license = "MIT" requires-python = ">=3.8" authors = [ { name = "Nikolaus Waxweiler", email = "nikolaus.waxweiler@daltonmaag.com" }, ] classifiers = [ "Development Status :: 5 - Production/Stable", "Programming Language :: Python", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ] dependencies = ["attrs >= 21.3", "cattrs >= 22.2", "fonttools[ufo] >= 4.11"] [project.urls] Homepage = "https://github.com/daltonmaag/statmake" [project.scripts] statmake = "statmake.cli:main" [dependency-groups] dev = [ "mypy", "pytest >= 8", "pytest-cov >= 5", "ruff >= 0.9", "ufo2ft >= 2.7", "ufoLib2 >= 0.4", ] [tool.hatch.version] source = "vcs" [tool.mypy] python_version = "3.8" platform = "linux" disallow_incomplete_defs = true disallow_untyped_defs = true no_implicit_optional = true strict_equality = true strict_optional = true warn_no_return = true warn_redundant_casts = true warn_unreachable = true [[tool.mypy.overrides]] module = "tests.*" disallow_untyped_defs = false [[tool.mypy.overrides]] module = [ "fontTools.*", "ufo2ft", "ufoLib2", "pytest", "testutil", "importlib_metadata", "exceptiongroup", "tomli", ] ignore_missing_imports = true [tool.pytest.ini_options] filterwarnings = [ "ignore::DeprecationWarning:fs", "ignore::DeprecationWarning:pkg_resources", ] statmake-2.0.1/src/000077500000000000000000000000001512571366100141215ustar00rootroot00000000000000statmake-2.0.1/src/statmake/000077500000000000000000000000001512571366100157325ustar00rootroot00000000000000statmake-2.0.1/src/statmake/__init__.py000066400000000000000000000003041512571366100200400ustar00rootroot00000000000000from importlib.metadata import PackageNotFoundError, version # type: ignore try: __version__ = version(__name__) except PackageNotFoundError: # pragma: no cover __version__ = "unknown" statmake-2.0.1/src/statmake/__main__.py000066400000000000000000000001101512571366100200140ustar00rootroot00000000000000import statmake.cli if __name__ == "__main__": statmake.cli.main() statmake-2.0.1/src/statmake/classes.py000066400000000000000000000263601512571366100177500ustar00rootroot00000000000000import enum import functools import os from pathlib import Path from typing import Any, Dict, List, Mapping, Optional, Sequence, Set, Tuple, Union import attrs import cattrs import fontTools.designspaceLib import fontTools.misc.plistlib from .errors import StylespaceError DESIGNSPACE_STYLESPACE_INLINE_KEY = "org.statmake.stylespace" DESIGNSPACE_STYLESPACE_PATH_KEY = "org.statmake.stylespacePath" class AxisValueFlag(enum.Flag): OlderSiblingFontAttribute = 0x0001 ElidableAxisValueName = 0x0002 @attrs.frozen class FlagList: """Represent a list of AxisValueFlags so I can implement a value property.""" flags: List[AxisValueFlag] = attrs.field(factory=list) @property def value(self) -> int: """Return the value of all flags ORed together.""" if not self.flags: return 0 return functools.reduce(lambda x, y: x | y, self.flags).value @attrs.frozen class NameRecord: """Represent a IETF BCP 47 language code to name string mapping for the `name` table.""" mapping: Mapping[str, str] def __attrs_post_init__(self) -> None: if "en" not in self.mapping: raise StylespaceError( "All NameRecords must have a default English (IETF BCP 47 language " "code 'en') entry." ) def __getitem__(self, key: str) -> str: return self.mapping.__getitem__(key) @property def default(self) -> str: return self.mapping["en"] @classmethod def from_string(cls, name: str) -> "NameRecord": return cls(mapping={"en": name}) @classmethod def from_dict(cls, dictionary: Mapping) -> "NameRecord": return cls(mapping=dictionary) @classmethod def structure(cls, data: Union[str, dict]) -> "NameRecord": if isinstance(data, str): return cls.from_string(data) if isinstance(data, dict): return cls.from_dict(data) raise StylespaceError(f"Don't know how to construct NameRecord from '{data}'.") @attrs.frozen class LocationFormat1: name: NameRecord value: float flags: FlagList = attrs.field(factory=FlagList) def to_builder_dict(self) -> Dict[str, Any]: return { "name": self.name.mapping, "value": self.value, "flags": self.flags.value, } @attrs.frozen class LocationFormat2: name: NameRecord value: float range: Tuple[float, float] flags: FlagList = attrs.field(factory=FlagList) def to_builder_dict(self) -> Dict[str, Any]: return { "name": self.name.mapping, "nominalValue": self.value, "rangeMinValue": self.range[0], "rangeMaxValue": self.range[1], "flags": self.flags.value, } @attrs.frozen class LocationFormat3: name: NameRecord value: float linked_value: float flags: FlagList = attrs.field(factory=FlagList) def to_builder_dict(self) -> Dict[str, Any]: return { "name": self.name.mapping, "value": self.value, "linkedValue": self.linked_value, "flags": self.flags.value, } @attrs.frozen class LocationFormat4: name: NameRecord axis_values: Mapping[str, float] flags: FlagList = attrs.field(factory=FlagList) def to_builder_dict(self, name_to_tag: Mapping[str, str]) -> Dict[str, Any]: return { "name": self.name.mapping, "location": {name_to_tag[k]: v for k, v in self.axis_values.items()}, "flags": self.flags.value, } @attrs.frozen class Axis: name: NameRecord tag: str locations: Sequence[Union[LocationFormat1, LocationFormat2, LocationFormat3]] = ( attrs.field(factory=list) ) ElidedFallback = Union[NameRecord, int] @attrs.frozen class Stylespace: axes: List[Axis] locations: List[LocationFormat4] = attrs.field(factory=list) elided_fallback_name_id: ElidedFallback = 2 def __attrs_post_init__(self) -> None: # Ensure named locations only contain axis names that are present in the # Stylespace and specify a location for all axes. available_axes = {a.name.default for a in self.axes} for named_location in self.locations: named_location_axes = set(named_location.axis_values.keys()) if named_location_axes != available_axes: raise StylespaceError( f"Location named '{named_location.name.default}' must specify " "values for all axes in the Stylespace and contain no other axis " "names." ) # Ensure that all name records have the same languages specified. reference_languages = None for axis in self.axes: if reference_languages is None: reference_languages = sorted(axis.name.mapping.keys()) for location in axis.locations: location_languages = sorted(location.name.mapping.keys()) if location_languages != reference_languages: raise StylespaceError( "All names must be supplied in the same languages. On axis " f"'{axis.name.default}', location '{location.name.default}' is " f"named in languages {location_languages} but " f"expected was {reference_languages}." ) for named_location in self.locations: assert reference_languages is not None location_languages = sorted(named_location.name.mapping.keys()) if location_languages != reference_languages: raise StylespaceError( "All names must be supplied in the same languages. The named " f"location '{named_location.name.default}' is " f"named in languages {location_languages} but " f"expected was {reference_languages}." ) # Ensure linked_values are present on the same axis in the Stylespace for axis in self.axes: values = {location.value for location in axis.locations} for location in axis.locations: linked_value: Optional[float] = getattr(location, "linked_value", None) if linked_value is not None and linked_value not in values: raise StylespaceError( f"On axis '{axis.name.default}', location " f"'{location.name.default}' specifies a linked_value of " f"'{linked_value}', which does not exist on that axis " "(ranges are ignored)." ) # Ensure location values are unique. for axis in self.axes: values = set() for location in axis.locations: if location.value in values: raise StylespaceError( f"On axis '{axis.name.default}', location " f"'{location.name.default}' specifies a duplicate location " f"value of '{location.value}', which is already assigned on " "the same axis." ) values.add(location.value) named_values: Set[Tuple[Tuple[str, float], ...]] = set() for named_location in self.locations: named_location_tuple = tuple(named_location.axis_values.items()) if named_location_tuple in named_values: raise StylespaceError( f"The named location '{named_location.name.default}' specifies a " "duplicate location already taken by another." ) named_values.add(named_location_tuple) @classmethod def from_dict( cls, dict_data: dict, detailed_validation: bool = False ) -> "Stylespace": """Construct Stylespace from unstructured dict data.""" converter = cattrs.Converter(detailed_validation=detailed_validation) converter.register_structure_hook( FlagList, lambda list_of_str_flags, cls: cls( # type: ignore [getattr(AxisValueFlag, f) for f in list_of_str_flags] ), ) converter.register_structure_hook( NameRecord, lambda data, cls: cls.structure(data), # type: ignore ) converter.register_structure_hook( ElidedFallback, lambda data, _cls: data if isinstance(data, int) else NameRecord.structure(data), # type: ignore ) return converter.structure(dict_data, cls) def to_dict(self) -> Dict[str, Any]: """Construct dict from structured Stylespace data.""" converter = cattrs.Converter() converter.register_unstructure_hook( # type: ignore FlagList, lambda cls: [flag.name for flag in cls.flags], # type: ignore ) converter.register_unstructure_hook(NameRecord, lambda cls: cls.mapping) # type: ignore return converter.unstructure(self) @classmethod def from_bytes( cls, stylespace_content: bytes, detailed_validation: bool = False ) -> "Stylespace": """Construct Stylespace from bytes containing (XML) plist data.""" stylespace_content_parsed = fontTools.misc.plistlib.loads(stylespace_content) return cls.from_dict(stylespace_content_parsed, detailed_validation) @classmethod def from_file( cls, stylespace_path: Union[str, bytes, os.PathLike], detailed_validation: bool = False, ) -> "Stylespace": """Construct Stylespace from path to (XML) plist file.""" with open(stylespace_path, "rb") as fp: return cls.from_bytes(fp.read(), detailed_validation) @classmethod def from_designspace( cls, designspace: fontTools.designspaceLib.DesignSpaceDocument ) -> "Stylespace": f"""Construct Stylespace from unstructured dict data or a path stored in a Designspace object's lib. The keys: - `{DESIGNSPACE_STYLESPACE_INLINE_KEY}`: The content of a regular Stylespace file as a dict. - `{DESIGNSPACE_STYLESPACE_PATH_KEY}`: A path to an external Stylespace file, relative to the Designspace file (the Designspace object must have the `path` attribute set). """ stylespace_inline = designspace.lib.get(DESIGNSPACE_STYLESPACE_INLINE_KEY) stylespace_path = designspace.lib.get(DESIGNSPACE_STYLESPACE_PATH_KEY) if (stylespace_inline and stylespace_path) or ( not stylespace_inline and not stylespace_path ): raise StylespaceError( "Designspace lib must contain EITHER inline Stylespace data OR a path " "to an external Stylespace file." ) if stylespace_inline: return cls.from_dict(stylespace_inline) if not isinstance(designspace.path, str): raise StylespaceError( "Designspace object must have `path` attribute set, because the " "Stylespace path is relative to the Designspace file." ) stylespace_path_lookup = Path(designspace.path).parent / stylespace_path # type: ignore return cls.from_file(stylespace_path_lookup) statmake-2.0.1/src/statmake/cli.py000066400000000000000000000044261512571366100170610ustar00rootroot00000000000000import argparse import logging import sys from pathlib import Path from typing import List, Optional import fontTools.designspaceLib import fontTools.ttLib import statmake import statmake.classes import statmake.lib from statmake.errors import Error, StylespaceError def main(args: Optional[List[str]] = None) -> None: logging.basicConfig(format="%(levelname)s: %(message)s") parser = argparse.ArgumentParser() parser.add_argument("--version", action="version", version=statmake.__version__) parser.add_argument( "--stylespace", type=statmake.classes.Stylespace.from_file, help=( "The path to the Stylespace file, if it is not contained in the " "Designspace." ), ) parser.add_argument( "--designspace", "-m", required=True, type=fontTools.designspaceLib.DesignSpaceDocument.fromfile, help="The path to the Designspace file used to generate the variable font.", ) parser.add_argument( "--output-path", type=Path, help="Write the modified font to this path instead of in-place.", ) parser.add_argument( "--mac-names", action="store_true", help="Generate legacy Mac name entries for each default Windows name entry.", ) parser.add_argument( "variable_font", type=Path, help="The path to the variable font file." ) parsed_args = parser.parse_args(args) designspace = parsed_args.designspace if parsed_args.stylespace: stylespace = parsed_args.stylespace else: try: stylespace = statmake.classes.Stylespace.from_designspace(designspace) except StylespaceError as e: logging.error("Could not load Stylespace data from Designspace: %s", str(e)) sys.exit(1) additional_locations = designspace.lib.get("org.statmake.additionalLocations", {}) font = fontTools.ttLib.TTFont(parsed_args.variable_font) try: statmake.lib.apply_stylespace_to_variable_font( stylespace, font, additional_locations, mac_names=parsed_args.mac_names ) except Error as e: logging.error("Cannot apply Stylespace to font: %s", str(e)) sys.exit(1) font.save(parsed_args.output_path or parsed_args.variable_font) statmake-2.0.1/src/statmake/errors.py000066400000000000000000000002131512571366100176140ustar00rootroot00000000000000class Error(Exception): """Base exception.""" class StylespaceError(Error): """Represents a consistency error in Stylespaces.""" statmake-2.0.1/src/statmake/lib.py000066400000000000000000000213111512571366100170500ustar00rootroot00000000000000import collections from typing import Any, Dict, List, Mapping, Set, Tuple, Union import fontTools.otlLib.builder import fontTools.ttLib from fontTools.ttLib.tables._f_v_a_r import table__f_v_a_r as FvarTable from fontTools.ttLib.tables._n_a_m_e import table__n_a_m_e as NameTable import statmake.classes from statmake.errors import Error def apply_stylespace_to_variable_font( stylespace: statmake.classes.Stylespace, varfont: fontTools.ttLib.TTFont, additional_locations: Mapping[str, float], mac_names: bool = False, ) -> None: """Generate and apply a STAT table to a variable font. additional_locations: used in subset Designspaces to express where on which other axes not defined by an element the varfont stands. The primary use-case is defining a complete STAT table for variable fonts that do not include all axes of a family (either because they intentionally contain just a subset of axes or because the designs are incompatible). mac_names: Whether to add a platformID=1 name record for every platformID=3 record. Off by default, because these are deprecated. """ axes, locations, elided_fallback_name = _generate_builder_data( stylespace, varfont, additional_locations ) fontTools.otlLib.builder.buildStatTable( varfont, axes, locations, elided_fallback_name, # type: ignore macNames=mac_names, ) def _generate_builder_data( stylespace: statmake.classes.Stylespace, varfont: fontTools.ttLib.TTFont, additional_locations: Mapping[str, float], ) -> Tuple[ List[Mapping[str, Any]], List[Mapping[str, Any]], Union[int, Dict[str, str]] ]: """Generate axes and locations dictionaries for use in fontTools.otlLib.builder.buildStatTable, tailored to the font. Rules: 1. There must be a fvar table so we know which named instances are defined. Every named instance needs a STAT entry for every point of its axis definition, i.e. an instance at {"Weight": 300, "Slant": 5} must have a Stylespace entry for Weight=300 and for Slant=5. 2. The Stylespace must contain all axis names the varfont does and tags must match. 3. Additional locations must only specify axes not in the font already and can only draw from axes available in the Stylespace. 4. All name IDs must have a default English (United States) entry for the Windows platform, Unicode BMP encoding, to match axis names to tags. 5. The font must get a location for every axis the Stylespace contains. """ name_to_tag = {a.name.default: a.tag for a in stylespace.axes} _sanity_check(stylespace, varfont, additional_locations, name_to_tag) # First, determine which stops are used on which axes. The STAT table must contain # a name for each stop that is used on each axis, so each stop must have an entry # in the Stylespace. Also include locations in additional_locations that can refer # to axes not present in the current varfont. stylespace_stops: Dict[str, Set[float]] = {} for axis in stylespace.axes: stylespace_stops[axis.tag] = {location.value for location in axis.locations} for named_location in stylespace.locations: for name, value in named_location.axis_values.items(): stylespace_stops[name_to_tag[name]].add(value) fvar = varfont["fvar"] assert isinstance(fvar, FvarTable) axis_stops: Mapping[str, Set[float]] = collections.defaultdict(set) # tag to stops for instance in fvar.instances: for k, v in instance.coordinates.items(): if v not in stylespace_stops[k]: raise Error( f"There is no Stylespace entry for stop {v} on the '{k}' axis." ) axis_stops[k].add(v) for k, v in additional_locations.items(): axis_tag = name_to_tag[k] if v not in stylespace_stops[axis_tag]: raise Error( f"There is no Stylespace entry for stop {v} on the '{k}' axis (from " "additional locations)." ) axis_stops[axis_tag].add(v) # Generate formats 1, 2 and 3. builder_axes: List[Mapping[str, Any]] = [ { "tag": axis.tag, "name": axis.name.mapping, "ordering": index, "values": [ location.to_builder_dict() for location in axis.locations if location.value in axis_stops[axis.tag] ], } for index, axis in enumerate(stylespace.axes) ] # Generate format 4. builder_locations: List[Mapping[str, Any]] = [ named_location.to_builder_dict(name_to_tag) for named_location in stylespace.locations if all( name_to_tag[k] in axis_stops and v in axis_stops[name_to_tag[k]] for k, v in named_location.axis_values.items() ) ] elided_fallback: Union[int, Mapping[str, str]] if isinstance(stylespace.elided_fallback_name_id, int): # Use a raw name ID directly. elided_fallback = stylespace.elided_fallback_name_id else: # Otherwise, unwrap into the format that the builder expects. elided_fallback = dict(stylespace.elided_fallback_name_id.mapping) return builder_axes, builder_locations, elided_fallback def _sanity_check( stylespace: statmake.classes.Stylespace, varfont: fontTools.ttLib.TTFont, additional_locations: Mapping[str, float], stylespace_name_to_tag: Mapping[str, str], ) -> None: """Ensures the input data contains no obvious faults.""" if "fvar" not in varfont: raise Error( "Need a variable font with the fvar table to determine which instances " "are present." ) fvar = varfont["fvar"] assert isinstance(fvar, FvarTable) # Sanity check: only allow axis names in additional_locations that are present in # the Stylespace. stylespace_names_set = set(stylespace_name_to_tag.keys()) additional_names_set = set(additional_locations.keys()) if not additional_names_set.issubset(stylespace_names_set): surplus_keys = ", ".join(additional_names_set - stylespace_names_set) raise Error( "Additional locations must only contain axis names that are present in " f"the Stylespace, the following aren't: {surplus_keys}." ) # Sanity check: Ensure all font axes are present in the Stylespace and tags match. font_name_to_tag = { _default_name_string(varfont, axis.axisNameID): axis.axisTag for axis in fvar.axes } for name, tag in font_name_to_tag.items(): if name not in stylespace_name_to_tag: raise Error( f"Font contains axis named '{name}' which is not in Stylespace. The " "Stylespace must contain all axes any font from the same family " "contains." ) if stylespace_name_to_tag[name] != tag: raise Error( f"Font axis named '{name}' has tag '{tag}' but Stylespace defines it " f"to be '{stylespace_name_to_tag[name]}'. Axis names and tags must " "match between the font and the Stylespace." ) # Sanity check: Only allow axis names in additional_locations that aren't in the # font already. for axis_name in additional_locations: if axis_name in font_name_to_tag: raise Error( f"Rejecting the additional location for the axis named '{axis_name}' " "because it is already present in the font." ) # Sanity check: Ensure the location of the font is fully specified. This means # the font axis names plus additional_locations axis names must equal Stylespace # axis names. font_names_set = set(font_name_to_tag.keys()).union(additional_names_set) if font_names_set != stylespace_names_set: missing_axis_names = ", ".join(stylespace_names_set - font_names_set) raise Error( "The location of the font is not fully specified, missing locations " f"for the following axes: {missing_axis_names}." ) # Sanity check: only allow raw fallback name IDs that are in this font. if isinstance(stylespace.elided_fallback_name_id, int): _default_name_string(varfont, stylespace.elided_fallback_name_id) def _default_name_string(otfont: fontTools.ttLib.TTFont, name_id: int) -> str: """Return English name for name_id.""" name_table = otfont["name"] assert isinstance(name_table, NameTable) name = name_table.getName(name_id, 3, 1, 0x409) if name is None: raise Error(f"No English record for id {name_id} for Windows platform.") return name.toStr() statmake-2.0.1/src/statmake/py.typed000066400000000000000000000000001512571366100174170ustar00rootroot00000000000000statmake-2.0.1/tests/000077500000000000000000000000001512571366100144745ustar00rootroot00000000000000statmake-2.0.1/tests/__init__.py000066400000000000000000000000001512571366100165730ustar00rootroot00000000000000statmake-2.0.1/tests/conftest.py000066400000000000000000000001731512571366100166740ustar00rootroot00000000000000from pathlib import Path import pytest @pytest.fixture def datadir() -> Path: return Path(__file__).parent / "data" statmake-2.0.1/tests/data/000077500000000000000000000000001512571366100154055ustar00rootroot00000000000000statmake-2.0.1/tests/data/Test.stylespace000066400000000000000000000145311512571366100204260ustar00rootroot00000000000000 axes name Weight tag wght locations name XLight value 200 name Light value 300 name Regular value 400 linked_value 700 flags ElidableAxisValueName name Semi Bold value 600 name en Bold value 700 name Black value 900 range 701 900 name Italic tag ital locations name Upright value 0 linked_value 1 flags ElidableAxisValueName name Italic value 1 locations name ASDF axis_values Weight 333 Italic 1 name fgfg axis_values Weight 650 Italic 0.5 flags ElidableAxisValueName elided_fallback_name_id Regular statmake-2.0.1/tests/data/TestBogusFormat4.stylespace000066400000000000000000000053611512571366100226640ustar00rootroot00000000000000 axes name Weight tag wght locations name XLight value 200 name Light value 300 name Regular value 400 linked_value 700 flags ElidableAxisValueName name Semi Bold value 600 name en Bold value 700 name Black value 900 range 701 900 name Italic tag ital locations name Upright value 0 linked_value 1 flags ElidableAxisValueName name Italic value 1 locations name ASDF axis_values Weight 333 statmake-2.0.1/tests/data/TestBogusFormat4_2.stylespace000066400000000000000000000054561512571366100231120ustar00rootroot00000000000000 axes name Weight tag wght locations name XLight value 200 name Light value 300 name Regular value 400 linked_value 700 flags ElidableAxisValueName name Semi Bold value 600 name en Bold value 700 name Black value 900 range 701 900 name Italic tag ital locations name Upright value 0 linked_value 1 flags ElidableAxisValueName name Italic value 1 locations name ASDF axis_values Weight 333 Fooooo 333 statmake-2.0.1/tests/data/TestBroken.stylespace000066400000000000000000000026371512571366100215730ustar00rootroot00000000000000 axes locations name Extra Light range 200 value 200 name Light range 250 350 value 300 name Weight tag wght locations name Italic value 1 name Italic tag ital elided_fallback_name_id 2 statmake-2.0.1/tests/data/TestDuplicateValue.stylespace000066400000000000000000000023651512571366100232600ustar00rootroot00000000000000 axes name Weight tag wght locations name Regular value 400 range 350 500 name Regular value 400 linked_value 700 flags ElidableAxisValueName name Bold value 700 statmake-2.0.1/tests/data/TestDuplicateValueFormat4.stylespace000066400000000000000000000022141512571366100245060ustar00rootroot00000000000000 axes name Weight tag wght locations locations name ASDF axis_values Weight 333 name fgfg axis_values Weight 333 flags ElidableAxisValueName statmake-2.0.1/tests/data/TestExternalStylespace.designspace000066400000000000000000000036131512571366100242760ustar00rootroot00000000000000 org.statmake.stylespacePath Test.stylespace org.statmake.additionalLocations Italic 0 statmake-2.0.1/tests/data/TestIncomplete.stylespace000066400000000000000000000042111512571366100224400ustar00rootroot00000000000000 axes name Weight tag wght locations name XLight value 200 name Light value 300 name Semi Bold value 600 name en Bold value 700 name Black value 900 range 701 900 name Italic tag ital locations name Upright value 0 linked_value 1 flags ElidableAxisValueName name Italic value 1 statmake-2.0.1/tests/data/TestInlineStylespace.designspace000066400000000000000000000110041512571366100237230ustar00rootroot00000000000000 org.statmake.stylespace axes name Weight tag wght locations name XLight value 200 name Light value 300 name Regular value 400 linked_value 700 flags ElidableAxisValueName name Semi Bold value 600 name en Bold value 700 name Black value 900 range 701 900 name Italic tag ital locations name Upright value 0 linked_value 1 flags ElidableAxisValueName name Italic value 1 org.statmake.additionalLocations Italic 0 statmake-2.0.1/tests/data/TestItalIsSlnt.stylespace000066400000000000000000000134531512571366100223770ustar00rootroot00000000000000 axes name Weight tag wght locations name XLight value 200 name Light value 300 name Regular value 400 linked_value 700 flags ElidableAxisValueName name Semi Bold value 600 name en Bold value 700 name Black value 900 range 701 900 name Italic tag slnt locations name Upright value 0 linked_value 1 flags ElidableAxisValueName name Italic value 1 locations name ASDF axis_values Weight 333 Italic 1 name fgfg axis_values Weight 650 Italic 0.5 flags ElidableAxisValueName statmake-2.0.1/tests/data/TestJustWght.stylespace000066400000000000000000000034451512571366100221300ustar00rootroot00000000000000 axes name Weight tag wght locations name XLight value 200 name Light value 300 name Regular value 400 linked_value 700 flags ElidableAxisValueName name Semi Bold value 600 name en Bold value 700 name Black value 900 range 701 900 statmake-2.0.1/tests/data/TestMissingLinkedValue.stylespace000066400000000000000000000033221512571366100241000ustar00rootroot00000000000000 axes name Weight tag wght locations name Regular value 400 linked_value 100 flags ElidableAxisValueName name en Bold value 700 name Italic tag ital locations name Upright value 0 linked_value 1 flags ElidableAxisValueName name Italic value 1 statmake-2.0.1/tests/data/TestMultilingual.stylespace000066400000000000000000000125411512571366100230140ustar00rootroot00000000000000 axes name en Weight de Gäwicht fr Géwicht tag wght locations name en Thin de Dünn fr Dûnn value 200 name en Light de Leicht fr vfdgf value 300 name en Regular de Regulär fr aaa value 400 linked_value 700 flags ElidableAxisValueName name en AA de BB fr CC value 600 name en Bold de Böld fr Bôld value 700 name en asdf de asdf fr asdf value 900 name en Italic de Italienisch fr Itâlic tag ital locations name en Upright fr Ûpright de Aufrecht value 0 linked_value 1 flags ElidableAxisValueName name en Italic de Italienisch fr Itâlic value 1 locations name en ASDF de ASDF fr ASDF axis_values Weight 333 Italic 1 name en FGFG de FGFG fr FGFG axis_values Weight 650 Italic 0.5 flags ElidableAxisValueName statmake-2.0.1/tests/data/TestMultilingualBrokenAxisNameLang.stylespace000066400000000000000000000051011512571366100263770ustar00rootroot00000000000000 axes name en Weight de Gäwicht tag wght locations name Light value 300 name en Regular de Regulär value 400 linked_value 700 flags ElidableAxisValueName name en Bold fr Bôld value 700 name en Italic de Italienisch tag ital locations name en Upright de Aufrecht value 0 linked_value 1 flags ElidableAxisValueName name en Italic de Italienisch value 1 statmake-2.0.1/tests/data/TestMultilingualBrokenLocNameLang.stylespace000066400000000000000000000030771512571366100262220ustar00rootroot00000000000000 axes name en Weight de Gäwicht tag wght locations name en Italic de Italienisch tag ital locations name en Upright de Aufrecht value 0 linked_value 1 flags ElidableAxisValueName name en Italic value 1 statmake-2.0.1/tests/data/TestMultilingualNoEn.stylespace000066400000000000000000000050071512571366100235730ustar00rootroot00000000000000 axes name de Gäwicht tag wght locations name Light value 300 name en Regular de Regulär value 400 linked_value 700 flags ElidableAxisValueName name en Bold fr Bôld value 700 name en Italic de Italienisch tag ital locations name en Upright de Aufrecht value 0 linked_value 1 flags ElidableAxisValueName name en Italic de Italienisch value 1 statmake-2.0.1/tests/data/TestNoFormat4.stylespace000066400000000000000000000011251512571366100221530ustar00rootroot00000000000000 axes name Weight tag wght locations name XLight value 200 statmake-2.0.1/tests/data/Test_WghtItal.designspace000066400000000000000000000106501512571366100223400ustar00rootroot00000000000000 statmake-2.0.1/tests/data/Test_WghtItal_Multilingual.designspace000066400000000000000000000050261512571366100250670ustar00rootroot00000000000000 statmake-2.0.1/tests/data/Test_Wght_Italic.designspace000066400000000000000000000043641512571366100230200ustar00rootroot00000000000000 org.statmake.additionalLocations Italic 1 statmake-2.0.1/tests/data/Test_Wght_Upright.designspace000066400000000000000000000040251512571366100232270ustar00rootroot00000000000000 org.statmake.additionalLocations Italic 0 statmake-2.0.1/tests/data/elided_fallback/000077500000000000000000000000001512571366100204525ustar00rootroot00000000000000statmake-2.0.1/tests/data/elided_fallback/Default.stylespace000066400000000000000000000022411512571366100241330ustar00rootroot00000000000000 axes name Weight tag wght locations name Regular value 400 linked_value 700 flags ElidableAxisValueName name en Bold value 700 statmake-2.0.1/tests/data/elided_fallback/Font.designspace000066400000000000000000000016001512571366100235640ustar00rootroot00000000000000 statmake-2.0.1/tests/data/elided_fallback/IntegerCorrect.stylespace000066400000000000000000000023531512571366100254720ustar00rootroot00000000000000 elided_fallback_name_id 3 axes name Weight tag wght locations name Regular value 400 linked_value 700 flags ElidableAxisValueName name en Bold value 700 statmake-2.0.1/tests/data/elided_fallback/IntegerInvalid.stylespace000066400000000000000000000024161512571366100254570ustar00rootroot00000000000000 elided_fallback_name_id 12345678 axes name Weight tag wght locations name Regular value 400 linked_value 700 flags ElidableAxisValueName name en Bold value 700 statmake-2.0.1/tests/data/elided_fallback/NameRecord.stylespace000066400000000000000000000024021512571366100245650ustar00rootroot00000000000000 elided_fallback_name_id expected axes name Weight tag wght locations name Regular value 400 linked_value 700 flags ElidableAxisValueName name en Bold value 700 statmake-2.0.1/tests/test_cli.py000066400000000000000000000101071512571366100166530ustar00rootroot00000000000000import fontTools.designspaceLib import fontTools.ttLib import pytest import ufo2ft import statmake.cli from . import testutil def test_cli_stylespace_in_designspace(datadir, tmp_path): varfont = empty_varfont(datadir / "Test_Wght_Upright.designspace") varfont.save(tmp_path / "varfont.ttf") del varfont statmake.cli.main( [ "-m", str(datadir / "TestInlineStylespace.designspace"), str(tmp_path / "varfont.ttf"), ] ) font = fontTools.ttLib.TTFont(tmp_path / "varfont.ttf") v = testutil.dump_axis_values(font, font["STAT"].table.AxisValueArray.AxisValue) assert v == TEST_WGHT_UPRIGHT_STAT_DUMP names = font["name"] assert not any(True for record in names.names if record.platformID == 1) def test_cli_stylespace_in_designspace_mac_names(datadir, tmp_path): varfont = empty_varfont(datadir / "Test_Wght_Upright.designspace") varfont.save(tmp_path / "varfont.ttf") del varfont statmake.cli.main( [ "-m", str(datadir / "TestInlineStylespace.designspace"), "--mac-names", str(tmp_path / "varfont.ttf"), ] ) varfont = fontTools.ttLib.TTFont(tmp_path / "varfont.ttf") names = varfont["name"] assert any(True for record in names.names if record.platformID == 1) def test_cli_designspace_stylespace_external(datadir, tmp_path): varfont = empty_varfont(datadir / "Test_Wght_Upright.designspace") varfont.save(tmp_path / "varfont.ttf") statmake.cli.main( [ "-m", str(datadir / "TestExternalStylespace.designspace"), str(tmp_path / "varfont.ttf"), ] ) font = fontTools.ttLib.TTFont(tmp_path / "varfont.ttf") v = testutil.dump_axis_values(font, font["STAT"].table.AxisValueArray.AxisValue) assert v == TEST_WGHT_UPRIGHT_STAT_DUMP def test_cli_stylespace_external(datadir, tmp_path): varfont = empty_varfont(datadir / "Test_Wght_Upright.designspace") varfont.save(tmp_path / "varfont.ttf") statmake.cli.main( [ "-m", str(datadir / "Test_Wght_Upright.designspace"), "--stylespace", str(datadir / "Test.stylespace"), str(tmp_path / "varfont.ttf"), ] ) font = fontTools.ttLib.TTFont(tmp_path / "varfont.ttf") v = testutil.dump_axis_values(font, font["STAT"].table.AxisValueArray.AxisValue) assert v == TEST_WGHT_UPRIGHT_STAT_DUMP def test_cli_stylespace_in_broken_designspace(datadir, tmp_path): with pytest.raises(SystemExit): statmake.cli.main( [ "-m", str(datadir / "Test_Wght_Upright.designspace"), str(tmp_path / "varfont.ttf"), ] ) def empty_varfont(designspace_path): designspace = fontTools.designspaceLib.DesignSpaceDocument.fromfile( designspace_path ) for source in designspace.sources: source.font = testutil.empty_UFO(source.styleName) ufo2ft.compileInterpolatableTTFsFromDS(designspace, inplace=True) varfont, _, _ = fontTools.varLib.build(designspace) return varfont TEST_WGHT_UPRIGHT_STAT_DUMP = [ {"Format": 1, "Name": {"en": "XLight"}, "Flags": 0, "AxisIndex": 0, "Value": 200.0}, {"Format": 1, "Name": {"en": "Light"}, "Flags": 0, "AxisIndex": 0, "Value": 300.0}, { "Format": 3, "Name": {"en": "Regular"}, "Flags": 2, "AxisIndex": 0, "Value": 400.0, "LinkedValue": 700.0, }, { "Format": 1, "Name": {"en": "Semi Bold"}, "Flags": 0, "AxisIndex": 0, "Value": 600.0, }, {"Format": 1, "Name": {"en": "Bold"}, "Flags": 0, "AxisIndex": 0, "Value": 700.0}, { "Format": 2, "Name": {"en": "Black"}, "Flags": 0, "AxisIndex": 0, "NominalValue": 900.0, "RangeMinValue": 701.0, "RangeMaxValue": 900.0, }, { "Format": 3, "Name": {"en": "Upright"}, "Flags": 2, "AxisIndex": 1, "Value": 0.0, "LinkedValue": 1.0, }, ] statmake-2.0.1/tests/test_elided_fallback.py000066400000000000000000000036761512571366100211660ustar00rootroot00000000000000import pytest from statmake.errors import Error from . import testutil def test_elided_fallback_default(datadir): """Test that the default value for the elided fallback name is name ID 2 when the stylespace key is omitted.""" varfont = testutil.generate_variable_font( datadir / "elided_fallback" / "Font.designspace", datadir / "elided_fallback" / "Default.stylespace", ) stat_table = varfont["STAT"] actual = stat_table.table.ElidedFallbackNameID assert actual == 2 def test_elided_fallback_int(datadir): """Test that an explicit integer name ID for the elided fallback name is parsed and applied from the stylespace.""" varfont = testutil.generate_variable_font( datadir / "elided_fallback" / "Font.designspace", datadir / "elided_fallback" / "IntegerCorrect.stylespace", ) stat_table = varfont["STAT"] actual = stat_table.table.ElidedFallbackNameID assert actual == 3 def test_elided_fallback_int_invalid(datadir): """Test that statmake will refuse to generate a STAT if the name ID integer specified for the elided fallback name does not exist in the final TTF.""" with pytest.raises( Error, match=r"No English record for id 12345678 for Windows platform" ): testutil.generate_variable_font( datadir / "elided_fallback" / "Font.designspace", datadir / "elided_fallback" / "IntegerInvalid.stylespace", ) def test_elided_fallback_name_record(datadir): """Test that an explicit NameRecord (e.g. a string) for the elided fallback name is parsed and applied from the stylespace.""" varfont = testutil.generate_variable_font( datadir / "elided_fallback" / "Font.designspace", datadir / "elided_fallback" / "NameRecord.stylespace", ) stat_table = varfont["STAT"] actual = varfont["name"].getDebugName(stat_table.table.ElidedFallbackNameID) assert actual == "expected" statmake-2.0.1/tests/test_make_stat.py000066400000000000000000000375541512571366100200730ustar00rootroot00000000000000import fontTools.designspaceLib import pytest import statmake.classes from statmake.errors import Error, StylespaceError from . import testutil def test_load_stylespace_broken_range(datadir): with pytest.raises(ValueError, match=r"Not enough values .*"): statmake.classes.Stylespace.from_file(datadir / "TestBroken.stylespace") def test_load_stylespace_broken_format4_1(datadir): with pytest.raises( StylespaceError, match=r".* must specify values for all axes .*" ): statmake.classes.Stylespace.from_file(datadir / "TestBogusFormat4.stylespace") def test_load_stylespace_broken_format4_2(datadir): with pytest.raises( StylespaceError, match=r".* must specify values for all axes .*" ): statmake.classes.Stylespace.from_file(datadir / "TestBogusFormat4_2.stylespace") def test_load_stylespace_missing_linked_value(datadir): with pytest.raises( StylespaceError, match=r".* location 'Regular' specifies a linked_value of '100.0'.*", ): statmake.classes.Stylespace.from_file( datadir / "TestMissingLinkedValue.stylespace" ) def test_load_stylespace_duplicate_value(datadir): with pytest.raises( StylespaceError, match=r".* 'Regular' specifies a duplicate location value of '400.0'.*", ): statmake.classes.Stylespace.from_file(datadir / "TestDuplicateValue.stylespace") def test_load_stylespace_duplicate_value_format4(datadir): with pytest.raises( StylespaceError, match=r".* location 'fgfg' specifies a duplicate location .*" ): statmake.classes.Stylespace.from_file( datadir / "TestDuplicateValueFormat4.stylespace" ) def test_load_stylespace_broken_multilingual_no_en(datadir): with pytest.raises(StylespaceError, match=r".* must have a default English .*"): statmake.classes.Stylespace.from_file( datadir / "TestMultilingualNoEn.stylespace" ) def test_load_stylespace_broken_multilingual_incomplete_lang(datadir): with pytest.raises( StylespaceError, match=r".* languages \['en'\] but expected was \['de', 'en'\]." ): statmake.classes.Stylespace.from_file( datadir / "TestMultilingualBrokenAxisNameLang.stylespace" ) def test_load_stylespace_broken_multilingual_incomplete_lang2(datadir): with pytest.raises( StylespaceError, match=r".* languages \['en'\] but expected was \['de', 'en'\]." ): statmake.classes.Stylespace.from_file( datadir / "TestMultilingualBrokenLocNameLang.stylespace" ) def test_load_stylespace_no_format4(datadir): statmake.classes.Stylespace.from_file(datadir / "TestNoFormat4.stylespace") def test_load_from_designspace(datadir): designspace = fontTools.designspaceLib.DesignSpaceDocument.fromfile( datadir / "TestInlineStylespace.designspace" ) statmake.classes.Stylespace.from_designspace(designspace) def test_load_from_broken_designspace(datadir): designspace = fontTools.designspaceLib.DesignSpaceDocument.fromfile( datadir / "TestNoFormat4.stylespace" ) with pytest.raises(StylespaceError, match=r".* lib .*"): statmake.classes.Stylespace.from_designspace(designspace) def test_generation_incomplete_stylespace(datadir): with pytest.raises(Error, match=r".* no Stylespace entry .*"): _ = testutil.generate_variable_font( datadir / "Test_Wght_Italic.designspace", datadir / "TestIncomplete.stylespace", ) def test_generation_incomplete_additional_location(datadir): with pytest.raises( Error, match=r".* no Stylespace entry .* additional locations.*" ): _ = testutil.generate_variable_font( datadir / "Test_Wght_Italic.designspace", datadir / "Test.stylespace", {"Italic": 2}, ) def test_generation_disjunct_additional_location(datadir): with pytest.raises(Error, match=r".* the following aren't: Foo."): _ = testutil.generate_variable_font( datadir / "Test_Wght_Italic.designspace", datadir / "Test.stylespace", {"Foo": 2}, ) def test_generation_superfluous_additional_location(datadir): with pytest.raises( Error, match=r"Rejecting the additional location for the axis named 'Italic'.*" ): _ = testutil.generate_variable_font( datadir / "Test_WghtItal.designspace", datadir / "Test.stylespace", {"Italic": 1}, ) def test_generation_unknown_font_axis(datadir): with pytest.raises( Error, match=r"Font contains axis named 'Italic' which is not in Stylespace.*" ): _ = testutil.generate_variable_font( datadir / "Test_WghtItal.designspace", datadir / "TestJustWght.stylespace", {}, ) def test_generation_wrong_tag(datadir): with pytest.raises( Error, match=r"Font axis named 'Italic' has tag 'ital' but Stylespace .* 'slnt'.", ): _ = testutil.generate_variable_font( datadir / "Test_WghtItal.designspace", datadir / "TestItalIsSlnt.stylespace", {}, ) def test_generation_incomplete_location(datadir): with pytest.raises( Error, match=r"missing locations for the following axes: Italic." ): _ = testutil.generate_variable_font( datadir / "Test_Wght_Italic.designspace", datadir / "Test.stylespace", {} ) def test_generation_full(datadir): varfont = testutil.generate_variable_font( datadir / "Test_WghtItal.designspace", datadir / "Test.stylespace" ) stat_table = varfont["STAT"] assert stat_table.table.Version == 0x00010002 stat_axes = testutil.dump_axes(varfont, stat_table.table.DesignAxisRecord.Axis) stat_axes_expected = [ {"Name": {"en": "Weight"}, "AxisTag": "wght", "AxisOrdering": 0}, {"Name": {"en": "Italic"}, "AxisTag": "ital", "AxisOrdering": 1}, ] assert stat_axes == stat_axes_expected stat_axis_values = testutil.dump_axis_values( varfont, stat_table.table.AxisValueArray.AxisValue ) stat_axis_values_expected = [ { "AxisIndex": 0, "Flags": 0, "Format": 1, "Name": {"en": "XLight"}, "Value": 200.0, }, { "AxisIndex": 0, "Flags": 0, "Format": 1, "Name": {"en": "Light"}, "Value": 300.0, }, { "AxisIndex": 0, "Flags": 2, "Format": 3, "LinkedValue": 700.0, "Name": {"en": "Regular"}, "Value": 400.0, }, { "AxisIndex": 0, "Flags": 0, "Format": 1, "Name": {"en": "Semi Bold"}, "Value": 600.0, }, { "AxisIndex": 0, "Flags": 0, "Format": 1, "Name": {"en": "Bold"}, "Value": 700.0, }, { "AxisIndex": 0, "Flags": 0, "Format": 2, "Name": {"en": "Black"}, "NominalValue": 900.0, "RangeMaxValue": 900.0, "RangeMinValue": 701.0, }, { "AxisIndex": 1, "Flags": 2, "Format": 3, "LinkedValue": 1.0, "Name": {"en": "Upright"}, "Value": 0.0, }, { "AxisIndex": 1, "Flags": 0, "Format": 1, "Name": {"en": "Italic"}, "Value": 1.0, }, { "AxisValueRecord": [(0, 333.0), (1, 1.0)], "Flags": 0, "Format": 4, "Name": {"en": "ASDF"}, }, { "AxisValueRecord": [(0, 650.0), (1, 0.5)], "Flags": 2, "Format": 4, "Name": {"en": "fgfg"}, }, ] assert sorted(stat_axis_values, key=lambda x: x["Name"]["en"]) == sorted( stat_axis_values_expected, key=lambda x: x["Name"]["en"] ) assert stat_table.table.ElidedFallbackNameID == 2 names = varfont["name"] assert not any(True for record in names.names if record.platformID == 1) def test_generation_full_mac_names(datadir): varfont = testutil.generate_variable_font( datadir / "Test_WghtItal.designspace", datadir / "Test.stylespace", mac_names=True, ) names = varfont["name"] assert any(True for record in names.names if record.platformID == 1) def test_generation_upright(datadir): varfont = testutil.generate_variable_font( datadir / "Test_Wght_Upright.designspace", datadir / "Test.stylespace" ) stat_table = varfont["STAT"] assert stat_table.table.Version == 0x00010001 stat_axes = testutil.dump_axes(varfont, stat_table.table.DesignAxisRecord.Axis) stat_axes_expected = [ {"Name": {"en": "Weight"}, "AxisTag": "wght", "AxisOrdering": 0}, {"Name": {"en": "Italic"}, "AxisTag": "ital", "AxisOrdering": 1}, ] assert stat_axes == stat_axes_expected stat_axis_values = testutil.dump_axis_values( varfont, stat_table.table.AxisValueArray.AxisValue ) stat_axis_values_expected = [ { "AxisIndex": 0, "Flags": 0, "Format": 1, "Name": {"en": "XLight"}, "Value": 200.0, }, { "AxisIndex": 0, "Flags": 0, "Format": 1, "Name": {"en": "Light"}, "Value": 300.0, }, { "AxisIndex": 0, "Flags": 2, "Format": 3, "LinkedValue": 700.0, "Name": {"en": "Regular"}, "Value": 400.0, }, { "AxisIndex": 0, "Flags": 0, "Format": 1, "Name": {"en": "Semi Bold"}, "Value": 600.0, }, { "AxisIndex": 0, "Flags": 0, "Format": 1, "Name": {"en": "Bold"}, "Value": 700.0, }, { "AxisIndex": 0, "Flags": 0, "Format": 2, "Name": {"en": "Black"}, "NominalValue": 900.0, "RangeMaxValue": 900.0, "RangeMinValue": 701.0, }, { "AxisIndex": 1, "Flags": 2, "Format": 3, "LinkedValue": 1.0, "Name": {"en": "Upright"}, "Value": 0.0, }, ] assert stat_axis_values == stat_axis_values_expected assert stat_table.table.ElidedFallbackNameID == 2 def test_generation_italic(datadir): varfont = testutil.generate_variable_font( datadir / "Test_Wght_Italic.designspace", datadir / "Test.stylespace" ) stat_table = varfont["STAT"] assert stat_table.table.Version == 0x00010002 stat_axes = testutil.dump_axes(varfont, stat_table.table.DesignAxisRecord.Axis) stat_axes_expected = [ {"Name": {"en": "Weight"}, "AxisTag": "wght", "AxisOrdering": 0}, {"Name": {"en": "Italic"}, "AxisTag": "ital", "AxisOrdering": 1}, ] assert stat_axes == stat_axes_expected stat_axis_values = testutil.dump_axis_values( varfont, stat_table.table.AxisValueArray.AxisValue ) stat_axis_values_expected = [ { "AxisIndex": 0, "Flags": 0, "Format": 1, "Name": {"en": "XLight"}, "Value": 200.0, }, { "AxisIndex": 0, "Flags": 0, "Format": 1, "Name": {"en": "Light"}, "Value": 300.0, }, { "AxisIndex": 0, "Flags": 2, "Format": 3, "LinkedValue": 700.0, "Name": {"en": "Regular"}, "Value": 400.0, }, { "AxisIndex": 0, "Flags": 0, "Format": 1, "Name": {"en": "Semi Bold"}, "Value": 600.0, }, { "AxisIndex": 0, "Flags": 0, "Format": 1, "Name": {"en": "Bold"}, "Value": 700.0, }, { "AxisIndex": 0, "Flags": 0, "Format": 2, "Name": {"en": "Black"}, "NominalValue": 900.0, "RangeMaxValue": 900.0, "RangeMinValue": 701.0, }, { "AxisIndex": 1, "Flags": 0, "Format": 1, "Name": {"en": "Italic"}, "Value": 1.0, }, { "AxisValueRecord": [(0, 333.0), (1, 1.0)], "Flags": 0, "Format": 4, "Name": {"en": "ASDF"}, }, ] assert sorted(stat_axis_values, key=lambda x: x["Name"]["en"]) == sorted( stat_axis_values_expected, key=lambda x: x["Name"]["en"] ) assert stat_table.table.ElidedFallbackNameID == 2 def test_generation_full_multilingual(datadir): varfont = testutil.generate_variable_font( datadir / "Test_WghtItal.designspace", datadir / "TestMultilingual.stylespace" ) stat_table = varfont["STAT"] assert stat_table.table.Version == 0x00010002 stat_axes = testutil.dump_axes(varfont, stat_table.table.DesignAxisRecord.Axis) stat_axes_expected = [ { "Name": {"de": "Gäwicht", "en": "Weight", "fr": "Géwicht"}, "AxisTag": "wght", "AxisOrdering": 0, }, { "Name": {"de": "Italienisch", "en": "Italic", "fr": "Itâlic"}, "AxisTag": "ital", "AxisOrdering": 1, }, ] assert stat_axes == stat_axes_expected stat_axis_values = testutil.dump_axis_values( varfont, stat_table.table.AxisValueArray.AxisValue ) stat_axis_values_expected = [ { "Format": 1, "Name": {"de": "Dünn", "en": "Thin", "fr": "Dûnn"}, "Flags": 0, "AxisIndex": 0, "Value": 200.0, }, { "Format": 1, "Name": {"de": "Leicht", "en": "Light", "fr": "vfdgf"}, "Flags": 0, "AxisIndex": 0, "Value": 300.0, }, { "Format": 3, "Name": {"de": "Regulär", "en": "Regular", "fr": "aaa"}, "Flags": 2, "AxisIndex": 0, "Value": 400.0, "LinkedValue": 700.0, }, { "Format": 1, "Name": {"de": "BB", "en": "AA", "fr": "CC"}, "Flags": 0, "AxisIndex": 0, "Value": 600.0, }, { "Format": 1, "Name": {"de": "Böld", "en": "Bold", "fr": "Bôld"}, "Flags": 0, "AxisIndex": 0, "Value": 700.0, }, { "Format": 1, "Name": {"de": "asdf", "en": "asdf", "fr": "asdf"}, "Flags": 0, "AxisIndex": 0, "Value": 900.0, }, { "Format": 3, "Name": {"de": "Aufrecht", "en": "Upright", "fr": "Ûpright"}, "Flags": 2, "AxisIndex": 1, "Value": 0.0, "LinkedValue": 1.0, }, { "Format": 1, "Name": {"de": "Italienisch", "en": "Italic", "fr": "Itâlic"}, "Flags": 0, "AxisIndex": 1, "Value": 1.0, }, { "Format": 4, "Name": {"de": "ASDF", "en": "ASDF", "fr": "ASDF"}, "Flags": 0, "AxisValueRecord": [(0, 333.0), (1, 1.0)], }, { "Format": 4, "Name": {"de": "FGFG", "en": "FGFG", "fr": "FGFG"}, "Flags": 2, "AxisValueRecord": [(0, 650.0), (1, 0.5)], }, ] assert sorted(stat_axis_values, key=lambda x: x["Name"]["en"]) == sorted( stat_axis_values_expected, key=lambda x: x["Name"]["en"] ) assert stat_table.table.ElidedFallbackNameID == 2 statmake-2.0.1/tests/test_serialize.py000066400000000000000000000004301512571366100200710ustar00rootroot00000000000000from pathlib import Path from statmake.classes import Stylespace def test_serialize(datadir: Path) -> None: stylespace = Stylespace.from_file(datadir / "Test.stylespace") stylespace_rt = Stylespace.from_dict(stylespace.to_dict()) assert stylespace == stylespace_rt statmake-2.0.1/tests/testutil.py000066400000000000000000000067611512571366100167350ustar00rootroot00000000000000import io from pathlib import Path from typing import Mapping, Optional import fontTools.designspaceLib import fontTools.ttLib import fontTools.ttLib.tables._n_a_m_e import fontTools.varLib import ufo2ft import ufoLib2 import statmake.classes import statmake.lib def dump_axes(font, axes_array): dump_list = [] for axis in axes_array: entry = { "Name": dump_name_ids(font, axis.AxisNameID), "AxisTag": axis.AxisTag, "AxisOrdering": axis.AxisOrdering, } dump_list.append(entry) return dump_list def dump_axis_values(font, axis_value_array): dump_list = [] for axis in axis_value_array: entry = { "Format": axis.Format, "Name": dump_name_ids(font, axis.ValueNameID), "Flags": axis.Flags, } if axis.Format == 1: entry["AxisIndex"] = axis.AxisIndex entry["Value"] = axis.Value elif axis.Format == 2: entry["AxisIndex"] = axis.AxisIndex entry["NominalValue"] = axis.NominalValue entry["RangeMinValue"] = axis.RangeMinValue entry["RangeMaxValue"] = axis.RangeMaxValue elif axis.Format == 3: entry["AxisIndex"] = axis.AxisIndex entry["Value"] = axis.Value entry["LinkedValue"] = axis.LinkedValue elif axis.Format == 4: entry["AxisValueRecord"] = [ (r.AxisIndex, r.Value) for r in axis.AxisValueRecord ] else: raise ValueError("Unknown format") dump_list.append(entry) return dump_list def dump_name_ids(otfont: fontTools.ttLib.TTFont, name_id: int) -> Mapping[str, str]: """Return a mapping of language codes to name strings.""" name_mapping = fontTools.ttLib.tables._n_a_m_e._WINDOWS_LANGUAGES name_table = otfont["name"].names matches = { name_mapping[n.langID]: n.toUnicode() for n in name_table if n.platformID == 3 and n.nameID == name_id } return matches def empty_UFO(style_name: str) -> ufoLib2.Font: # pylint: disable=assigning-non-slot ufo = ufoLib2.Font() ufo.info.familyName = "Test" ufo.info.styleName = style_name ufo.info.unitsPerEm = 1000 ufo.info.ascender = 800 ufo.info.descender = -200 ufo.info.xHeight = 500 ufo.info.capHeight = 700 ufo.info.postscriptUnderlineThickness = 50 ufo.info.postscriptUnderlinePosition = -75 g = ufo.newGlyph("a") g.width = 500 return ufo def reload_font(font): buf = io.BytesIO() font.save(buf) buf.seek(0) return fontTools.ttLib.TTFont(buf) def generate_variable_font( designspace_path: Path, stylespace_path: Path, additional_locations: Optional[Mapping[str, float]] = None, mac_names: bool = False, ) -> fontTools.ttLib.TTFont: designspace = fontTools.designspaceLib.DesignSpaceDocument.fromfile( designspace_path ) for source in designspace.sources: source.font = empty_UFO(source.styleName) ufo2ft.compileInterpolatableTTFsFromDS(designspace, inplace=True) varfont, _, _ = fontTools.varLib.build(designspace) stylespace = statmake.classes.Stylespace.from_file(stylespace_path) if additional_locations is None: additional_locations = designspace.lib.get( "org.statmake.additionalLocations", {} ) statmake.lib.apply_stylespace_to_variable_font( stylespace, varfont, additional_locations, mac_names=mac_names ) return reload_font(varfont) statmake-2.0.1/tox.ini000066400000000000000000000020271512571366100146460ustar00rootroot00000000000000[tox] isolated_build = true envlist = lint, clean-cov, py3{8,9,10,11,12,13}-cov, pypy3{8,9,10}-cov, report-cov [testenv] runner = uv-venv-lock-runner with_dev = true package = wheel wheel_build_env = .pkg depends = # See https://pytest-cov.readthedocs.io/en/latest/tox.html. py3{8,9,10,11,12,13}-cov,pypy3{8,9,10}-cov: clean report: py3{8,9,10,11,12,13}-cov,pypy3{8,9,10}-cov commands = pytest --cov --cov-append --cov-report=term-missing {posargs} [testenv:clean-cov] runner = uv-venv-lock-runner with_dev = true skip_install = true commands = coverage erase [testenv:report-cov] runner = uv-venv-lock-runner with_dev = true skip_install = true commands = coverage report coverage html [testenv:format] runner = uv-venv-lock-runner with_dev = true commands = ruff check --select I --fix ruff format [testenv:lint] runner = uv-venv-lock-runner with_dev = true skip_install = true commands = ruff check mypy src tests [testenv:upgrade-requirements] skip_install = true commands = uv lock --upgrade statmake-2.0.1/uv.lock000066400000000000000000003173221512571366100146460ustar00rootroot00000000000000version = 1 requires-python = ">=3.8" resolution-markers = [ "python_full_version >= '3.9'", "python_full_version < '3.9'", ] [[package]] name = "appdirs" version = "1.4.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d7/d8/05696357e0311f5b5c316d7b95f46c669dd9c15aaeecbb48c7d0aeb88c40/appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", size = 13470 } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128", size = 9566 }, ] [[package]] name = "attrs" version = "24.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/48/c8/6260f8ccc11f0917360fc0da435c5c9c7504e3db174d5a12a1494887b045/attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", size = 805984 } wheels = [ { url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397 }, ] [[package]] name = "booleanoperations" version = "0.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fonttools" }, { name = "pyclipper" }, ] sdist = { url = "https://files.pythonhosted.org/packages/57/d9/9eae7bc4ba3a38ab7426522fb08e12df54aec27595d7bcd1bc0670aec873/booleanOperations-0.9.0.zip", hash = "sha256:8cfa821c32ad374fa120d6b2e0b444ebeac57c91e6631528645fa19ac2a281b8", size = 202950 } wheels = [ { url = "https://files.pythonhosted.org/packages/fc/c6/c4cae54f482465a33c5f011d95ec64293dce9e012dac7873147c2dc85396/booleanOperations-0.9.0-py3-none-any.whl", hash = "sha256:86c291c2fba9faedff6f007c932d7f242dd9b4304e9c6ca8149f864d07877a59", size = 18480 }, ] [[package]] name = "cattrs" version = "24.1.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/64/65/af6d57da2cb32c076319b7489ae0958f746949d407109e3ccf4d115f147c/cattrs-24.1.2.tar.gz", hash = "sha256:8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85", size = 426462 } wheels = [ { url = "https://files.pythonhosted.org/packages/c8/d5/867e75361fc45f6de75fe277dd085627a9db5ebb511a87f27dc1396b5351/cattrs-24.1.2-py3-none-any.whl", hash = "sha256:67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0", size = 66446 }, ] [[package]] name = "cffsubr" version = "0.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fonttools" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a7/34/189fac2e58cfe3104bdbcc0ba9e28aa32559ff7b1bf23369be0cfd86b1a0/cffsubr-0.3.0.tar.gz", hash = "sha256:7745150bdb81679facdd11c1f3b87096c4f4dbd4957e8fcebb88c45687952efb", size = 17830033 } wheels = [ { url = "https://files.pythonhosted.org/packages/fa/d0/a0189efd0e9372057c7eec3c4ef7f4173d71cbb78649631aaebbc470c34c/cffsubr-0.3.0-py3-none-macosx_10_9_universal2.whl", hash = "sha256:7a961d46faef6f35a965d088eb9f1d09c1ad069b4c838cc7ec61550352a539d9", size = 794666 }, { url = "https://files.pythonhosted.org/packages/9c/ad/6b54807c9e6184dbd843bf16415e918083f15e4a4d871d74d3aa34cf0bd4/cffsubr-0.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a0cec38325cf77005605031b65b21afee7192db71996736932274abadcdccfe", size = 1075963 }, { url = "https://files.pythonhosted.org/packages/91/c8/37b7f14d70f02212240a56ec78f4c5a7afd0f29170922c2da12a6f419375/cffsubr-0.3.0-py3-none-win32.whl", hash = "sha256:eb1fcde72824d947a2ef2525c21817620adbaac1ae33676c66b65aa60d669a4b", size = 794121 }, { url = "https://files.pythonhosted.org/packages/30/47/256b36787b5b31c8d43a0b2d9974cfa55d2314b06da3d0d006ae8de50afa/cffsubr-0.3.0-py3-none-win_amd64.whl", hash = "sha256:c000336bbdd81a7814806f502cd255cfdfd7c10bcec8cb51fe60e0f1f2d9f62e", size = 965943 }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] [[package]] name = "coverage" version = "7.6.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/f7/08/7e37f82e4d1aead42a7443ff06a1e406aabf7302c4f00a546e4b320b994c/coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", size = 798791 } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/61/eb7ce5ed62bacf21beca4937a90fe32545c91a3c8a42a30c6616d48fc70d/coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", size = 206690 }, { url = "https://files.pythonhosted.org/packages/7d/73/041928e434442bd3afde5584bdc3f932fb4562b1597629f537387cec6f3d/coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", size = 207127 }, { url = "https://files.pythonhosted.org/packages/c7/c8/6ca52b5147828e45ad0242388477fdb90df2c6cbb9a441701a12b3c71bc8/coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", size = 235654 }, { url = "https://files.pythonhosted.org/packages/d5/da/9ac2b62557f4340270942011d6efeab9833648380109e897d48ab7c1035d/coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc", size = 233598 }, { url = "https://files.pythonhosted.org/packages/53/23/9e2c114d0178abc42b6d8d5281f651a8e6519abfa0ef460a00a91f80879d/coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", size = 234732 }, { url = "https://files.pythonhosted.org/packages/0f/7e/a0230756fb133343a52716e8b855045f13342b70e48e8ad41d8a0d60ab98/coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", size = 233816 }, { url = "https://files.pythonhosted.org/packages/28/7c/3753c8b40d232b1e5eeaed798c875537cf3cb183fb5041017c1fdb7ec14e/coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", size = 232325 }, { url = "https://files.pythonhosted.org/packages/57/e3/818a2b2af5b7573b4b82cf3e9f137ab158c90ea750a8f053716a32f20f06/coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", size = 233418 }, { url = "https://files.pythonhosted.org/packages/c8/fb/4532b0b0cefb3f06d201648715e03b0feb822907edab3935112b61b885e2/coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", size = 209343 }, { url = "https://files.pythonhosted.org/packages/5a/25/af337cc7421eca1c187cc9c315f0a755d48e755d2853715bfe8c418a45fa/coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", size = 210136 }, { url = "https://files.pythonhosted.org/packages/ad/5f/67af7d60d7e8ce61a4e2ddcd1bd5fb787180c8d0ae0fbd073f903b3dd95d/coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", size = 206796 }, { url = "https://files.pythonhosted.org/packages/e1/0e/e52332389e057daa2e03be1fbfef25bb4d626b37d12ed42ae6281d0a274c/coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", size = 207244 }, { url = "https://files.pythonhosted.org/packages/aa/cd/766b45fb6e090f20f8927d9c7cb34237d41c73a939358bc881883fd3a40d/coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", size = 239279 }, { url = "https://files.pythonhosted.org/packages/70/6c/a9ccd6fe50ddaf13442a1e2dd519ca805cbe0f1fcd377fba6d8339b98ccb/coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", size = 236859 }, { url = "https://files.pythonhosted.org/packages/14/6f/8351b465febb4dbc1ca9929505202db909c5a635c6fdf33e089bbc3d7d85/coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", size = 238549 }, { url = "https://files.pythonhosted.org/packages/68/3c/289b81fa18ad72138e6d78c4c11a82b5378a312c0e467e2f6b495c260907/coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", size = 237477 }, { url = "https://files.pythonhosted.org/packages/ed/1c/aa1efa6459d822bd72c4abc0b9418cf268de3f60eeccd65dc4988553bd8d/coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", size = 236134 }, { url = "https://files.pythonhosted.org/packages/fb/c8/521c698f2d2796565fe9c789c2ee1ccdae610b3aa20b9b2ef980cc253640/coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", size = 236910 }, { url = "https://files.pythonhosted.org/packages/7d/30/033e663399ff17dca90d793ee8a2ea2890e7fdf085da58d82468b4220bf7/coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", size = 209348 }, { url = "https://files.pythonhosted.org/packages/20/05/0d1ccbb52727ccdadaa3ff37e4d2dc1cd4d47f0c3df9eb58d9ec8508ca88/coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", size = 210230 }, { url = "https://files.pythonhosted.org/packages/7e/d4/300fc921dff243cd518c7db3a4c614b7e4b2431b0d1145c1e274fd99bd70/coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", size = 206983 }, { url = "https://files.pythonhosted.org/packages/e1/ab/6bf00de5327ecb8db205f9ae596885417a31535eeda6e7b99463108782e1/coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", size = 207221 }, { url = "https://files.pythonhosted.org/packages/92/8f/2ead05e735022d1a7f3a0a683ac7f737de14850395a826192f0288703472/coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", size = 240342 }, { url = "https://files.pythonhosted.org/packages/0f/ef/94043e478201ffa85b8ae2d2c79b4081e5a1b73438aafafccf3e9bafb6b5/coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", size = 237371 }, { url = "https://files.pythonhosted.org/packages/1f/0f/c890339dd605f3ebc269543247bdd43b703cce6825b5ed42ff5f2d6122c7/coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", size = 239455 }, { url = "https://files.pythonhosted.org/packages/d1/04/7fd7b39ec7372a04efb0f70c70e35857a99b6a9188b5205efb4c77d6a57a/coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", size = 238924 }, { url = "https://files.pythonhosted.org/packages/ed/bf/73ce346a9d32a09cf369f14d2a06651329c984e106f5992c89579d25b27e/coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", size = 237252 }, { url = "https://files.pythonhosted.org/packages/86/74/1dc7a20969725e917b1e07fe71a955eb34bc606b938316bcc799f228374b/coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", size = 238897 }, { url = "https://files.pythonhosted.org/packages/b6/e9/d9cc3deceb361c491b81005c668578b0dfa51eed02cd081620e9a62f24ec/coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", size = 209606 }, { url = "https://files.pythonhosted.org/packages/47/c8/5a2e41922ea6740f77d555c4d47544acd7dc3f251fe14199c09c0f5958d3/coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", size = 210373 }, { url = "https://files.pythonhosted.org/packages/8c/f9/9aa4dfb751cb01c949c990d136a0f92027fbcc5781c6e921df1cb1563f20/coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", size = 207007 }, { url = "https://files.pythonhosted.org/packages/b9/67/e1413d5a8591622a46dd04ff80873b04c849268831ed5c304c16433e7e30/coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", size = 207269 }, { url = "https://files.pythonhosted.org/packages/14/5b/9dec847b305e44a5634d0fb8498d135ab1d88330482b74065fcec0622224/coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", size = 239886 }, { url = "https://files.pythonhosted.org/packages/7b/b7/35760a67c168e29f454928f51f970342d23cf75a2bb0323e0f07334c85f3/coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", size = 237037 }, { url = "https://files.pythonhosted.org/packages/f7/95/d2fd31f1d638df806cae59d7daea5abf2b15b5234016a5ebb502c2f3f7ee/coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", size = 239038 }, { url = "https://files.pythonhosted.org/packages/6e/bd/110689ff5752b67924efd5e2aedf5190cbbe245fc81b8dec1abaffba619d/coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", size = 238690 }, { url = "https://files.pythonhosted.org/packages/d3/a8/08d7b38e6ff8df52331c83130d0ab92d9c9a8b5462f9e99c9f051a4ae206/coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", size = 236765 }, { url = "https://files.pythonhosted.org/packages/d6/6a/9cf96839d3147d55ae713eb2d877f4d777e7dc5ba2bce227167d0118dfe8/coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", size = 238611 }, { url = "https://files.pythonhosted.org/packages/74/e4/7ff20d6a0b59eeaab40b3140a71e38cf52547ba21dbcf1d79c5a32bba61b/coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", size = 209671 }, { url = "https://files.pythonhosted.org/packages/35/59/1812f08a85b57c9fdb6d0b383d779e47b6f643bc278ed682859512517e83/coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", size = 210368 }, { url = "https://files.pythonhosted.org/packages/9c/15/08913be1c59d7562a3e39fce20661a98c0a3f59d5754312899acc6cb8a2d/coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", size = 207758 }, { url = "https://files.pythonhosted.org/packages/c4/ae/b5d58dff26cade02ada6ca612a76447acd69dccdbb3a478e9e088eb3d4b9/coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", size = 208035 }, { url = "https://files.pythonhosted.org/packages/b8/d7/62095e355ec0613b08dfb19206ce3033a0eedb6f4a67af5ed267a8800642/coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", size = 250839 }, { url = "https://files.pythonhosted.org/packages/7c/1e/c2967cb7991b112ba3766df0d9c21de46b476d103e32bb401b1b2adf3380/coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", size = 246569 }, { url = "https://files.pythonhosted.org/packages/8b/61/a7a6a55dd266007ed3b1df7a3386a0d760d014542d72f7c2c6938483b7bd/coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", size = 248927 }, { url = "https://files.pythonhosted.org/packages/c8/fa/13a6f56d72b429f56ef612eb3bc5ce1b75b7ee12864b3bd12526ab794847/coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", size = 248401 }, { url = "https://files.pythonhosted.org/packages/75/06/0429c652aa0fb761fc60e8c6b291338c9173c6aa0f4e40e1902345b42830/coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", size = 246301 }, { url = "https://files.pythonhosted.org/packages/52/76/1766bb8b803a88f93c3a2d07e30ffa359467810e5cbc68e375ebe6906efb/coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", size = 247598 }, { url = "https://files.pythonhosted.org/packages/66/8b/f54f8db2ae17188be9566e8166ac6df105c1c611e25da755738025708d54/coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", size = 210307 }, { url = "https://files.pythonhosted.org/packages/9f/b0/e0dca6da9170aefc07515cce067b97178cefafb512d00a87a1c717d2efd5/coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", size = 211453 }, { url = "https://files.pythonhosted.org/packages/81/d0/d9e3d554e38beea5a2e22178ddb16587dbcbe9a1ef3211f55733924bf7fa/coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0", size = 206674 }, { url = "https://files.pythonhosted.org/packages/38/ea/cab2dc248d9f45b2b7f9f1f596a4d75a435cb364437c61b51d2eb33ceb0e/coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a", size = 207101 }, { url = "https://files.pythonhosted.org/packages/ca/6f/f82f9a500c7c5722368978a5390c418d2a4d083ef955309a8748ecaa8920/coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b", size = 236554 }, { url = "https://files.pythonhosted.org/packages/a6/94/d3055aa33d4e7e733d8fa309d9adf147b4b06a82c1346366fc15a2b1d5fa/coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3", size = 234440 }, { url = "https://files.pythonhosted.org/packages/e4/6e/885bcd787d9dd674de4a7d8ec83faf729534c63d05d51d45d4fa168f7102/coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de", size = 235889 }, { url = "https://files.pythonhosted.org/packages/f4/63/df50120a7744492710854860783d6819ff23e482dee15462c9a833cc428a/coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6", size = 235142 }, { url = "https://files.pythonhosted.org/packages/3a/5d/9d0acfcded2b3e9ce1c7923ca52ccc00c78a74e112fc2aee661125b7843b/coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569", size = 233805 }, { url = "https://files.pythonhosted.org/packages/c4/56/50abf070cb3cd9b1dd32f2c88f083aab561ecbffbcd783275cb51c17f11d/coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989", size = 234655 }, { url = "https://files.pythonhosted.org/packages/25/ee/b4c246048b8485f85a2426ef4abab88e48c6e80c74e964bea5cd4cd4b115/coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7", size = 209296 }, { url = "https://files.pythonhosted.org/packages/5c/1c/96cf86b70b69ea2b12924cdf7cabb8ad10e6130eab8d767a1099fbd2a44f/coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8", size = 210137 }, { url = "https://files.pythonhosted.org/packages/19/d3/d54c5aa83268779d54c86deb39c1c4566e5d45c155369ca152765f8db413/coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255", size = 206688 }, { url = "https://files.pythonhosted.org/packages/a5/fe/137d5dca72e4a258b1bc17bb04f2e0196898fe495843402ce826a7419fe3/coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8", size = 207120 }, { url = "https://files.pythonhosted.org/packages/78/5b/a0a796983f3201ff5485323b225d7c8b74ce30c11f456017e23d8e8d1945/coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2", size = 235249 }, { url = "https://files.pythonhosted.org/packages/4e/e1/76089d6a5ef9d68f018f65411fcdaaeb0141b504587b901d74e8587606ad/coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a", size = 233237 }, { url = "https://files.pythonhosted.org/packages/9a/6f/eef79b779a540326fee9520e5542a8b428cc3bfa8b7c8f1022c1ee4fc66c/coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc", size = 234311 }, { url = "https://files.pythonhosted.org/packages/75/e1/656d65fb126c29a494ef964005702b012f3498db1a30dd562958e85a4049/coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004", size = 233453 }, { url = "https://files.pythonhosted.org/packages/68/6a/45f108f137941a4a1238c85f28fd9d048cc46b5466d6b8dda3aba1bb9d4f/coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb", size = 231958 }, { url = "https://files.pythonhosted.org/packages/9b/e7/47b809099168b8b8c72ae311efc3e88c8d8a1162b3ba4b8da3cfcdb85743/coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36", size = 232938 }, { url = "https://files.pythonhosted.org/packages/52/80/052222ba7058071f905435bad0ba392cc12006380731c37afaf3fe749b88/coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c", size = 209352 }, { url = "https://files.pythonhosted.org/packages/b8/d8/1b92e0b3adcf384e98770a00ca095da1b5f7b483e6563ae4eb5e935d24a1/coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca", size = 210153 }, { url = "https://files.pythonhosted.org/packages/a5/2b/0354ed096bca64dc8e32a7cbcae28b34cb5ad0b1fe2125d6d99583313ac0/coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", size = 198926 }, ] [package.optional-dependencies] toml = [ { name = "tomli", marker = "python_full_version < '3.9'" }, ] [[package]] name = "coverage" version = "7.6.10" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/84/ba/ac14d281f80aab516275012e8875991bb06203957aa1e19950139238d658/coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", size = 803868 } wheels = [ { url = "https://files.pythonhosted.org/packages/c5/12/2a2a923edf4ddabdffed7ad6da50d96a5c126dae7b80a33df7310e329a1e/coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78", size = 207982 }, { url = "https://files.pythonhosted.org/packages/ca/49/6985dbca9c7be3f3cb62a2e6e492a0c88b65bf40579e16c71ae9c33c6b23/coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c", size = 208414 }, { url = "https://files.pythonhosted.org/packages/35/93/287e8f1d1ed2646f4e0b2605d14616c9a8a2697d0d1b453815eb5c6cebdb/coverage-7.6.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a", size = 236860 }, { url = "https://files.pythonhosted.org/packages/de/e1/cfdb5627a03567a10031acc629b75d45a4ca1616e54f7133ca1fa366050a/coverage-7.6.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165", size = 234758 }, { url = "https://files.pythonhosted.org/packages/6d/85/fc0de2bcda3f97c2ee9fe8568f7d48f7279e91068958e5b2cc19e0e5f600/coverage-7.6.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988", size = 235920 }, { url = "https://files.pythonhosted.org/packages/79/73/ef4ea0105531506a6f4cf4ba571a214b14a884630b567ed65b3d9c1975e1/coverage-7.6.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5", size = 234986 }, { url = "https://files.pythonhosted.org/packages/c6/4d/75afcfe4432e2ad0405c6f27adeb109ff8976c5e636af8604f94f29fa3fc/coverage-7.6.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3", size = 233446 }, { url = "https://files.pythonhosted.org/packages/86/5b/efee56a89c16171288cafff022e8af44f8f94075c2d8da563c3935212871/coverage-7.6.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5", size = 234566 }, { url = "https://files.pythonhosted.org/packages/f2/db/67770cceb4a64d3198bf2aa49946f411b85ec6b0a9b489e61c8467a4253b/coverage-7.6.10-cp310-cp310-win32.whl", hash = "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244", size = 210675 }, { url = "https://files.pythonhosted.org/packages/8d/27/e8bfc43f5345ec2c27bc8a1fa77cdc5ce9dcf954445e11f14bb70b889d14/coverage-7.6.10-cp310-cp310-win_amd64.whl", hash = "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e", size = 211518 }, { url = "https://files.pythonhosted.org/packages/85/d2/5e175fcf6766cf7501a8541d81778fd2f52f4870100e791f5327fd23270b/coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3", size = 208088 }, { url = "https://files.pythonhosted.org/packages/4b/6f/06db4dc8fca33c13b673986e20e466fd936235a6ec1f0045c3853ac1b593/coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43", size = 208536 }, { url = "https://files.pythonhosted.org/packages/0d/62/c6a0cf80318c1c1af376d52df444da3608eafc913b82c84a4600d8349472/coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132", size = 240474 }, { url = "https://files.pythonhosted.org/packages/a3/59/750adafc2e57786d2e8739a46b680d4fb0fbc2d57fbcb161290a9f1ecf23/coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f", size = 237880 }, { url = "https://files.pythonhosted.org/packages/2c/f8/ef009b3b98e9f7033c19deb40d629354aab1d8b2d7f9cfec284dbedf5096/coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994", size = 239750 }, { url = "https://files.pythonhosted.org/packages/a6/e2/6622f3b70f5f5b59f705e680dae6db64421af05a5d1e389afd24dae62e5b/coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99", size = 238642 }, { url = "https://files.pythonhosted.org/packages/2d/10/57ac3f191a3c95c67844099514ff44e6e19b2915cd1c22269fb27f9b17b6/coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd", size = 237266 }, { url = "https://files.pythonhosted.org/packages/ee/2d/7016f4ad9d553cabcb7333ed78ff9d27248ec4eba8dd21fa488254dff894/coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377", size = 238045 }, { url = "https://files.pythonhosted.org/packages/a7/fe/45af5c82389a71e0cae4546413266d2195c3744849669b0bab4b5f2c75da/coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8", size = 210647 }, { url = "https://files.pythonhosted.org/packages/db/11/3f8e803a43b79bc534c6a506674da9d614e990e37118b4506faf70d46ed6/coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609", size = 211508 }, { url = "https://files.pythonhosted.org/packages/86/77/19d09ea06f92fdf0487499283b1b7af06bc422ea94534c8fe3a4cd023641/coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853", size = 208281 }, { url = "https://files.pythonhosted.org/packages/b6/67/5479b9f2f99fcfb49c0d5cf61912a5255ef80b6e80a3cddba39c38146cf4/coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078", size = 208514 }, { url = "https://files.pythonhosted.org/packages/15/d1/febf59030ce1c83b7331c3546d7317e5120c5966471727aa7ac157729c4b/coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", size = 241537 }, { url = "https://files.pythonhosted.org/packages/4b/7e/5ac4c90192130e7cf8b63153fe620c8bfd9068f89a6d9b5f26f1550f7a26/coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", size = 238572 }, { url = "https://files.pythonhosted.org/packages/dc/03/0334a79b26ecf59958f2fe9dd1f5ab3e2f88db876f5071933de39af09647/coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", size = 240639 }, { url = "https://files.pythonhosted.org/packages/d7/45/8a707f23c202208d7b286d78ad6233f50dcf929319b664b6cc18a03c1aae/coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", size = 240072 }, { url = "https://files.pythonhosted.org/packages/66/02/603ce0ac2d02bc7b393279ef618940b4a0535b0868ee791140bda9ecfa40/coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", size = 238386 }, { url = "https://files.pythonhosted.org/packages/04/62/4e6887e9be060f5d18f1dd58c2838b2d9646faf353232dec4e2d4b1c8644/coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", size = 240054 }, { url = "https://files.pythonhosted.org/packages/5c/74/83ae4151c170d8bd071924f212add22a0e62a7fe2b149edf016aeecad17c/coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359", size = 210904 }, { url = "https://files.pythonhosted.org/packages/c3/54/de0893186a221478f5880283119fc40483bc460b27c4c71d1b8bba3474b9/coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247", size = 211692 }, { url = "https://files.pythonhosted.org/packages/25/6d/31883d78865529257bf847df5789e2ae80e99de8a460c3453dbfbe0db069/coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9", size = 208308 }, { url = "https://files.pythonhosted.org/packages/70/22/3f2b129cc08de00c83b0ad6252e034320946abfc3e4235c009e57cfeee05/coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b", size = 208565 }, { url = "https://files.pythonhosted.org/packages/97/0a/d89bc2d1cc61d3a8dfe9e9d75217b2be85f6c73ebf1b9e3c2f4e797f4531/coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690", size = 241083 }, { url = "https://files.pythonhosted.org/packages/4c/81/6d64b88a00c7a7aaed3a657b8eaa0931f37a6395fcef61e53ff742b49c97/coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18", size = 238235 }, { url = "https://files.pythonhosted.org/packages/9a/0b/7797d4193f5adb4b837207ed87fecf5fc38f7cc612b369a8e8e12d9fa114/coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c", size = 240220 }, { url = "https://files.pythonhosted.org/packages/65/4d/6f83ca1bddcf8e51bf8ff71572f39a1c73c34cf50e752a952c34f24d0a60/coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd", size = 239847 }, { url = "https://files.pythonhosted.org/packages/30/9d/2470df6aa146aff4c65fee0f87f58d2164a67533c771c9cc12ffcdb865d5/coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e", size = 237922 }, { url = "https://files.pythonhosted.org/packages/08/dd/723fef5d901e6a89f2507094db66c091449c8ba03272861eaefa773ad95c/coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694", size = 239783 }, { url = "https://files.pythonhosted.org/packages/3d/f7/64d3298b2baf261cb35466000628706ce20a82d42faf9b771af447cd2b76/coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6", size = 210965 }, { url = "https://files.pythonhosted.org/packages/d5/58/ec43499a7fc681212fe7742fe90b2bc361cdb72e3181ace1604247a5b24d/coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e", size = 211719 }, { url = "https://files.pythonhosted.org/packages/ab/c9/f2857a135bcff4330c1e90e7d03446b036b2363d4ad37eb5e3a47bbac8a6/coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe", size = 209050 }, { url = "https://files.pythonhosted.org/packages/aa/b3/f840e5bd777d8433caa9e4a1eb20503495709f697341ac1a8ee6a3c906ad/coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273", size = 209321 }, { url = "https://files.pythonhosted.org/packages/85/7d/125a5362180fcc1c03d91850fc020f3831d5cda09319522bcfa6b2b70be7/coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8", size = 252039 }, { url = "https://files.pythonhosted.org/packages/a9/9c/4358bf3c74baf1f9bddd2baf3756b54c07f2cfd2535f0a47f1e7757e54b3/coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098", size = 247758 }, { url = "https://files.pythonhosted.org/packages/cf/c7/de3eb6fc5263b26fab5cda3de7a0f80e317597a4bad4781859f72885f300/coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb", size = 250119 }, { url = "https://files.pythonhosted.org/packages/3e/e6/43de91f8ba2ec9140c6a4af1102141712949903dc732cf739167cfa7a3bc/coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0", size = 249597 }, { url = "https://files.pythonhosted.org/packages/08/40/61158b5499aa2adf9e37bc6d0117e8f6788625b283d51e7e0c53cf340530/coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf", size = 247473 }, { url = "https://files.pythonhosted.org/packages/50/69/b3f2416725621e9f112e74e8470793d5b5995f146f596f133678a633b77e/coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2", size = 248737 }, { url = "https://files.pythonhosted.org/packages/3c/6e/fe899fb937657db6df31cc3e61c6968cb56d36d7326361847440a430152e/coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312", size = 211611 }, { url = "https://files.pythonhosted.org/packages/1c/55/52f5e66142a9d7bc93a15192eba7a78513d2abf6b3558d77b4ca32f5f424/coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d", size = 212781 }, { url = "https://files.pythonhosted.org/packages/40/41/473617aadf9a1c15bc2d56be65d90d7c29bfa50a957a67ef96462f7ebf8e/coverage-7.6.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a", size = 207978 }, { url = "https://files.pythonhosted.org/packages/10/f6/480586607768b39a30e6910a3c4522139094ac0f1677028e1f4823688957/coverage-7.6.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27", size = 208415 }, { url = "https://files.pythonhosted.org/packages/f1/af/439bb760f817deff6f4d38fe7da08d9dd7874a560241f1945bc3b4446550/coverage-7.6.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4", size = 236452 }, { url = "https://files.pythonhosted.org/packages/d0/13/481f4ceffcabe29ee2332e60efb52e4694f54a402f3ada2bcec10bb32e43/coverage-7.6.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f", size = 234374 }, { url = "https://files.pythonhosted.org/packages/c5/59/4607ea9d6b1b73e905c7656da08d0b00cdf6e59f2293ec259e8914160025/coverage-7.6.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25", size = 235505 }, { url = "https://files.pythonhosted.org/packages/85/60/d66365723b9b7f29464b11d024248ed3523ce5aab958e4ad8c43f3f4148b/coverage-7.6.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315", size = 234616 }, { url = "https://files.pythonhosted.org/packages/74/f8/2cf7a38e7d81b266f47dfcf137fecd8fa66c7bdbd4228d611628d8ca3437/coverage-7.6.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90", size = 233099 }, { url = "https://files.pythonhosted.org/packages/50/2b/bff6c1c6b63c4396ea7ecdbf8db1788b46046c681b8fcc6ec77db9f4ea49/coverage-7.6.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d", size = 234089 }, { url = "https://files.pythonhosted.org/packages/bf/b5/baace1c754d546a67779358341aa8d2f7118baf58cac235db457e1001d1b/coverage-7.6.10-cp39-cp39-win32.whl", hash = "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18", size = 210701 }, { url = "https://files.pythonhosted.org/packages/b1/bf/9e1e95b8b20817398ecc5a1e8d3e05ff404e1b9fb2185cd71561698fe2a2/coverage-7.6.10-cp39-cp39-win_amd64.whl", hash = "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59", size = 211482 }, { url = "https://files.pythonhosted.org/packages/a1/70/de81bfec9ed38a64fc44a77c7665e20ca507fc3265597c28b0d989e4082e/coverage-7.6.10-pp39.pp310-none-any.whl", hash = "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f", size = 200223 }, ] [package.optional-dependencies] toml = [ { name = "tomli", marker = "python_full_version >= '3.9' and python_full_version <= '3.11'" }, ] [[package]] name = "exceptiongroup" version = "1.2.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } wheels = [ { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, ] [[package]] name = "fontmath" version = "0.9.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fonttools" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0d/ee/c23438eb01ee4b43beb79c148088589661a3eb1c6549ec82baebea059c99/fontmath-0.9.4.zip", hash = "sha256:1fd9190c9d784e1305c3c49771b91d910f246a4b7c44ede219c99a07ed7aeda4", size = 39399 } wheels = [ { url = "https://files.pythonhosted.org/packages/80/2b/a70e202f2d314a3ebbaad02d6471cb6dcf5fa796f744f969f37a2ed038d9/fontMath-0.9.4-py2.py3-none-any.whl", hash = "sha256:ccb7a55709530520f112ebfbf5f5aa6be8c63e5baecab7a26c18a146e000a498", size = 32280 }, ] [[package]] name = "fonttools" version = "4.55.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/13/8d/8912cdde6a2b4c19ced69ea5790cd17d1c095a3c0104c1c936a1de804a64/fonttools-4.55.4.tar.gz", hash = "sha256:9598af0af85073659facbe9612fcc56b071ef2f26e3819ebf9bd8c5d35f958c5", size = 3498560 } wheels = [ { url = "https://files.pythonhosted.org/packages/06/84/da14576ce30bbed3c882bfc4de84d2e4348c65b1382688812357cb21416a/fonttools-4.55.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3b332ea7b7f5f3d99f9bc5a28a23c3824ae72711abf7c4e1d62fa21699fdebe7", size = 2774346 }, { url = "https://files.pythonhosted.org/packages/50/1d/3da7148a5552871c5dbe368de755602a0df0672e339edc133ed3e9704f2a/fonttools-4.55.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d8f925909256e62152e7c3e192655dbca3ab8c3cdef7d7b436732727e80feb6", size = 2302782 }, { url = "https://files.pythonhosted.org/packages/1b/9d/6b5be027fbfc8eab302d89608fc158b37531f3116506062e0d7183546465/fonttools-4.55.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a58af9b98e39bcd773aa352b4512be79b472830b799cb1d3cafb2b4796b71cd", size = 4584269 }, { url = "https://files.pythonhosted.org/packages/53/6f/c5ccd4c8f90fd7f6964a1b8981e58f5cc6361acedb0a473a8dae4e1ac3c6/fonttools-4.55.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:736d750d2ab4523067d8058e5294b40b01f2eee521e0fd401bec0d5e21e80b12", size = 4626917 }, { url = "https://files.pythonhosted.org/packages/c7/ea/53c4c75212b30d257e0865d6905eb6747ec7450b414caff742ff031eb758/fonttools-4.55.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1a9a2e7e8a9d3bfa9589db3e6c4e4c127fec252493924b2f87a67a25f9430057", size = 4581220 }, { url = "https://files.pythonhosted.org/packages/04/4f/05d9bf9595d75ece4d65e52bd994431cff575e11f00a9444ac8b2781091e/fonttools-4.55.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:87824368e994af34a95cb4279a8c711e51974b3c28d052d39d768531cc9e8e59", size = 4750636 }, { url = "https://files.pythonhosted.org/packages/43/21/d91c8d4583e0f6ee8e08868d5ab3de44f78af8da37d47e265f5b433bd0e2/fonttools-4.55.4-cp310-cp310-win32.whl", hash = "sha256:6c36dcbfe64bce38c4d4f1d436cdc6445e969eee96eb98d98be603b5abf8c3f2", size = 2177793 }, { url = "https://files.pythonhosted.org/packages/b8/33/c26363a57f5e766f38c84fb4e34d26d32a26398804f72e12a00c007166a1/fonttools-4.55.4-cp310-cp310-win_amd64.whl", hash = "sha256:3c53a467e5cf629acdbefc98b0f554859539fb6447bbeae4117b9ab51464ccc5", size = 2222313 }, { url = "https://files.pythonhosted.org/packages/5c/22/cf0707f681486bf91f998c3a6a6492d806d1cf09445ce01b26a724917439/fonttools-4.55.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1605b28165c785bf26c2cbd205dc0822463e3f9f56f187049eb214dc5f4a59cb", size = 2775483 }, { url = "https://files.pythonhosted.org/packages/09/79/11a07753a7b9ef46eaaa5e85b72558095713060aeca1393057a081fb21e3/fonttools-4.55.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d851d8b2fdb676507365d1430c3285d62c4039d0d7760d8cf2f2e5ea3aa19d73", size = 2303701 }, { url = "https://files.pythonhosted.org/packages/93/67/173994471ddb0ff8cd45b0a2ff9fa03416152ca90bd14d1cbe1ff75fb66c/fonttools-4.55.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fb3cf1cddf08cec0338f238f950cb76fabab23a324a579e3e1f9b2ef2578329", size = 4891469 }, { url = "https://files.pythonhosted.org/packages/16/b9/22e8be0fceaed86187ba35a1035b309e47575c68ee6ace3b66f146300f43/fonttools-4.55.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddd3208b06186ca00fbd329c0d0fed5ba209c99017cc46e2c4ea42233c2fbd00", size = 4920672 }, { url = "https://files.pythonhosted.org/packages/cc/15/ed0f0a9d303419e7c885b3a71bfe70bb71c8f964e5b1d515056e38551c69/fonttools-4.55.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9bd98819cb585a894dda9dcb337afeb2601abf17da17de7bfbfc1bc2e4a062c7", size = 4899903 }, { url = "https://files.pythonhosted.org/packages/b5/02/bd0da57dac3f44f37898b058659cf3beedbfd89b7d0f4b10761c9602dc1b/fonttools-4.55.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4877376c10541e8dccf14876c8476d5082338fa5d21103894894382cc245144b", size = 5067979 }, { url = "https://files.pythonhosted.org/packages/a0/b9/c232b07c0ecaba9e522695780ca8d711b099bf87889a19a6b35a4ebfde90/fonttools-4.55.4-cp311-cp311-win32.whl", hash = "sha256:3a5e466894ec6d8a009b0eb8e02a6eb26959a318d5b7a906280c26bdadce6423", size = 2176681 }, { url = "https://files.pythonhosted.org/packages/e3/50/2aa1cf2492e6aded4320122aed690268e97076aba1f418c0b4c68fb11a50/fonttools-4.55.4-cp311-cp311-win_amd64.whl", hash = "sha256:f595129e6f9c6402965d6295fe8c18c1945d27af0f90bdb52ff426226e647afc", size = 2223239 }, { url = "https://files.pythonhosted.org/packages/7a/ee/c7f06da45f60c076677291470599eb9f8aae6605cbfbebbcb8ee12428e26/fonttools-4.55.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b3db72ad2d26a0e9ec694cbfb4485a8da9c095d29f66561cf935dbd19f3efcea", size = 2769913 }, { url = "https://files.pythonhosted.org/packages/d9/a9/19aa6a9685d0bb285678850bfa22365a8376c590a7aaacc9f03d3a43beaa/fonttools-4.55.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:87717808fd5953588c3ffaf512e8cab0e43c09c1da04e42ba87fa4c07d8170c7", size = 2301168 }, { url = "https://files.pythonhosted.org/packages/00/63/88740f4333008336844aadbc9f7ef85d50e2eed779a5c33e13907a2439eb/fonttools-4.55.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f49dac626ad5bc1a0147b88e6157e3211fd440d00007f0da6c9e5f91dd5cb88e", size = 4806195 }, { url = "https://files.pythonhosted.org/packages/7b/fa/1d103fe6e9bf174afd1c04772ca4f88e8f577f44d37b7cc8644fe5ff2620/fonttools-4.55.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2d0ac8656ada8b604ae5da15d9aa075232f2181b95b51a3a2a55195222df7e7", size = 4877282 }, { url = "https://files.pythonhosted.org/packages/b8/53/1cdd447f30598950e4bf8a2de8cd1f6573e6cb34b726cf23713a3cd8fb1e/fonttools-4.55.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:013c8b45873fa77a4ff6d25e43fecf1046cb7e8c6b32f1843117f98f3f8eac60", size = 4784688 }, { url = "https://files.pythonhosted.org/packages/71/21/edfdcd85c1cce918d410909759a8db667f95bf3faed88141b1abfa2cefe1/fonttools-4.55.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:94caad375d254a0332926512f06791f5e66c24a913ebecd6178b14f61d27c62f", size = 5012253 }, { url = "https://files.pythonhosted.org/packages/7d/e7/7c16717b75e40f735e01d899ee152a0573e90be0e6b8fc2d47c16ba8239c/fonttools-4.55.4-cp312-cp312-win32.whl", hash = "sha256:cb3eb4bf3a0c4e431e1ccab7a33ef4f1bb32657133fff4a61dc4fcbd54b94d29", size = 2165283 }, { url = "https://files.pythonhosted.org/packages/50/ff/85d1c1d396a3ceaabcf7cb543da56d2223d9b76429bafd6c87f4a4e880df/fonttools-4.55.4-cp312-cp312-win_amd64.whl", hash = "sha256:6914269f6ff6b20c6b5a9b19d0b752880bd8ee218d9a7d6afe9960bbf1922d98", size = 2212080 }, { url = "https://files.pythonhosted.org/packages/09/9b/e7505e7f08c291ab28e6b5c7ae9fe92aab10f5c4b3666fc67eb59f6e454b/fonttools-4.55.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:699dd32da7258a89939567a3d71b3f8decf84da54488a2526693f0d981a76479", size = 2757277 }, { url = "https://files.pythonhosted.org/packages/7c/15/a26ae0e5be690038cf1d62277f1007282d4d355dc30dbf0a95224fe69b0e/fonttools-4.55.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f374b18ac04fbf78f20940418aee7882be3cdcb328ded80e16c3356499f64cf", size = 2294678 }, { url = "https://files.pythonhosted.org/packages/71/6a/20863c8ddf4dc7fd290b5ffddfc83d5918447523001b67a2dc81a0899b0d/fonttools-4.55.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b18792529ca3c24259090b6faa60bd0bdfcc4a06312e8f06d6fccab007f07193", size = 4784624 }, { url = "https://files.pythonhosted.org/packages/94/2f/c74fa21fddd6a4c22c80f2f86820a0c960a5c0f8f46407bc9c1e1c9b9f50/fonttools-4.55.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e91d25261ebc9ff2143b95e6272f46b9f28e260b8f40feda07c80b66ff7e61d", size = 4856618 }, { url = "https://files.pythonhosted.org/packages/00/37/1e9f1cb3b2454adac0b5fe85e940ea8d4eb174a9338e47020ec7d3cf1057/fonttools-4.55.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2695781a897395d03504fd24b60c944726b5e7b7af9ea3d922f7319d70c6fc37", size = 4765002 }, { url = "https://files.pythonhosted.org/packages/ff/fa/36b815132a71b9df13e9c52cd198194b48eb31f9a6d041f3ec6476d8b74f/fonttools-4.55.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21de3ef5b8e5361fd01d6aef2c09dda4ede139d6b3a1f5cf621d6bea48840dfd", size = 4985906 }, { url = "https://files.pythonhosted.org/packages/73/9a/51eb1cdc08d0883c40a3ea6d9a8ecd862bac587371bc92e0f35315688994/fonttools-4.55.4-cp313-cp313-win32.whl", hash = "sha256:0ef33fda14e39aabb892a18ed16805b0b5b4e8a801fd1815a694be9dc7f30024", size = 2163286 }, { url = "https://files.pythonhosted.org/packages/2b/a0/6fdeb063dfb401e3efc342ef8ff6cd9e290d9895c3777dbc3850842eb1ad/fonttools-4.55.4-cp313-cp313-win_amd64.whl", hash = "sha256:e953b1614e32b6da828ae7659c8f330a593b6c4b7a4a31f8f63c01b12f0d3680", size = 2209022 }, { url = "https://files.pythonhosted.org/packages/00/3d/9708f07f77d1a192f33a258e806a024d88a9cae7151a4b1b6f319c54afb5/fonttools-4.55.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e2d1bbcaf8ca8c60fbb029982197fbaa487559d5380f1c3098882c5ceb4311c7", size = 2772059 }, { url = "https://files.pythonhosted.org/packages/b1/55/d7e19d70582a24d1f253a28e6050ac66615f9e92eb4d3ee3ca8d98fa9bbf/fonttools-4.55.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a885593dbcbfc250ff17831f7dc9316e95c3d046e6cd7ff7ab52ebf673bbf978", size = 2301480 }, { url = "https://files.pythonhosted.org/packages/89/44/c3c1b6e99816c3e9da52ad542ac80298deb2d2ffa38a268e726d0bf17d3f/fonttools-4.55.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02cd4ad9b3ab9f9c5b233b3bb6a96a036c9c0ef17487805b5e73cedf6439d188", size = 4665520 }, { url = "https://files.pythonhosted.org/packages/6f/96/9ac06f31b90c82f01b164f4eac793f740866f3afd0c7765f17bac4236732/fonttools-4.55.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:822d46676f794bb6cac055b43f5636792e2a360e18cf0f3a0333c21d79ec0f2d", size = 4709579 }, { url = "https://files.pythonhosted.org/packages/0e/82/5b740fac932e680606911d075e441bbec0c63e6e20d731f2420a4cc165cf/fonttools-4.55.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:7b195440fe14d8601053a51e06e13c94f725bf9f964611be99dc3cb65497ce8e", size = 4687378 }, { url = "https://files.pythonhosted.org/packages/f1/91/642e8e977529d5513a9d610e6a2d602a83040cf93bd80ec21e0e512bf88e/fonttools-4.55.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a0e0a0ec8cc4b8f82f9cf4efa26774dbd93433ba51b8f9bd2b214bf36c5638f6", size = 4866395 }, { url = "https://files.pythonhosted.org/packages/56/cd/683e7ace393fb72acb024b6b23161131a3b503fa7e60cacec13ceb6fbccb/fonttools-4.55.4-cp38-cp38-win32.whl", hash = "sha256:ca7e6047fbc995500e0b7459a04d5b92cafd7730b636d5f83334cd7eefdf95c7", size = 1502616 }, { url = "https://files.pythonhosted.org/packages/ce/67/4e5aa4a5563a576c5cd5dd2f448bc527f9faec445c9b08bc489d3d251098/fonttools-4.55.4-cp38-cp38-win_amd64.whl", hash = "sha256:0185983fcf49ae7a826cedc6f64d68b0434a5b7905d89e75bc95fced7fe118c1", size = 1547689 }, { url = "https://files.pythonhosted.org/packages/fc/9d/09954e57e4c06237ba0dee2565feeb31e49113320504b93e759c967bcb0e/fonttools-4.55.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:dcc08dcb2be554073a72f3a8cecbc4226602ccdd0187b8f37a03a731cb931864", size = 2777045 }, { url = "https://files.pythonhosted.org/packages/aa/68/d8416c7709a30b7b3eff0b7d51fd366508ebe2d22f1f20e7c40029ce0c48/fonttools-4.55.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7b9b414ce50f09cb692e97ff82b041ea1a21076ed9c1923206560c15ce9ad03a", size = 2304043 }, { url = "https://files.pythonhosted.org/packages/84/21/2737e0e65e51c4f5cc07cfb2f23afee20096ed5a4d596a9f7ad9bcf3e148/fonttools-4.55.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8807a1357d434ef1f4aed9bdfee7077f52dbc040b18ac98f6e417f69a48afbb5", size = 4589859 }, { url = "https://files.pythonhosted.org/packages/a0/2e/e3d7f01f03424aa7b8cbf2b99825a28ba9df556bbb51b31464185d870682/fonttools-4.55.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93a3ec7cba2e71edbc999ce3d48d34ef87cc30a36af6ff90dfc0dbc131f705fc", size = 4634830 }, { url = "https://files.pythonhosted.org/packages/c3/6c/536159ebc77f88504124e79091c40c0663f9f048585ff7be8ab582204045/fonttools-4.55.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2964b9fe6b4a892a41a8a517bac232072a821cf2288fad1d19c6c1d19c34b0dd", size = 4583331 }, { url = "https://files.pythonhosted.org/packages/63/d6/3c59783c4beab00d13af1bff3121f354c6c1b1fc41f22e18ac2d08f2375a/fonttools-4.55.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0b9f4f032295adeb39a8c0eefb08a7b1e90f4b7571506e5d84bb923a7afa8247", size = 4753600 }, { url = "https://files.pythonhosted.org/packages/e7/7b/c55f7a001722bbb52b9eb8506ca1c5fe797bfc5434ad60df8945a649c572/fonttools-4.55.4-cp39-cp39-win32.whl", hash = "sha256:ee4e86280dc637a17e926cbdd32c2de148c013c3468777ae6e94c8b4449c8e93", size = 2178356 }, { url = "https://files.pythonhosted.org/packages/c1/bf/e664a9c3d61cb1fd91cdd2d332d8039292d8d4a07d81b8675026cc2d4556/fonttools-4.55.4-cp39-cp39-win_amd64.whl", hash = "sha256:82a03920f0f524abab375dcfac8926d9596986503ee00ae435bdd71b1498f214", size = 2222836 }, { url = "https://files.pythonhosted.org/packages/f3/5d/29b126e12df844432e188d19e74f47c2578fa5a72a122b4f41819e1e0923/fonttools-4.55.4-py3-none-any.whl", hash = "sha256:d07ad8f31038c6394a0945752458313367a0ef8125d284ee59f99e68393a3c2d", size = 1111964 }, ] [package.optional-dependencies] ufo = [ { name = "fs" }, ] [[package]] name = "fs" version = "2.4.16" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "appdirs" }, { name = "setuptools", version = "75.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "setuptools", version = "75.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, { name = "six" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5d/a9/af5bfd5a92592c16cdae5c04f68187a309be8a146b528eac3c6e30edbad2/fs-2.4.16.tar.gz", hash = "sha256:ae97c7d51213f4b70b6a958292530289090de3a7e15841e108fbe144f069d313", size = 187441 } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/5c/a3d95dc1ec6cdeb032d789b552ecc76effa3557ea9186e1566df6aac18df/fs-2.4.16-py2.py3-none-any.whl", hash = "sha256:660064febbccda264ae0b6bace80a8d1be9e089e0a5eb2427b7d517f9a91545c", size = 135261 }, ] [[package]] name = "iniconfig" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] [[package]] name = "mypy" version = "1.14.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/eb/2c92d8ea1e684440f54fa49ac5d9a5f19967b7b472a281f419e69a8d228e/mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6", size = 3216051 } wheels = [ { url = "https://files.pythonhosted.org/packages/9b/7a/87ae2adb31d68402da6da1e5f30c07ea6063e9f09b5e7cfc9dfa44075e74/mypy-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52686e37cf13d559f668aa398dd7ddf1f92c5d613e4f8cb262be2fb4fedb0fcb", size = 11211002 }, { url = "https://files.pythonhosted.org/packages/e1/23/eada4c38608b444618a132be0d199b280049ded278b24cbb9d3fc59658e4/mypy-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fb545ca340537d4b45d3eecdb3def05e913299ca72c290326be19b3804b39c0", size = 10358400 }, { url = "https://files.pythonhosted.org/packages/43/c9/d6785c6f66241c62fd2992b05057f404237deaad1566545e9f144ced07f5/mypy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90716d8b2d1f4cd503309788e51366f07c56635a3309b0f6a32547eaaa36a64d", size = 12095172 }, { url = "https://files.pythonhosted.org/packages/c3/62/daa7e787770c83c52ce2aaf1a111eae5893de9e004743f51bfcad9e487ec/mypy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae753f5c9fef278bcf12e1a564351764f2a6da579d4a81347e1d5a15819997b", size = 12828732 }, { url = "https://files.pythonhosted.org/packages/1b/a2/5fb18318a3637f29f16f4e41340b795da14f4751ef4f51c99ff39ab62e52/mypy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0fe0f5feaafcb04505bcf439e991c6d8f1bf8b15f12b05feeed96e9e7bf1427", size = 13012197 }, { url = "https://files.pythonhosted.org/packages/28/99/e153ce39105d164b5f02c06c35c7ba958aaff50a2babba7d080988b03fe7/mypy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d54bd85b925e501c555a3227f3ec0cfc54ee8b6930bd6141ec872d1c572f81f", size = 9780836 }, { url = "https://files.pythonhosted.org/packages/da/11/a9422850fd506edbcdc7f6090682ecceaf1f87b9dd847f9df79942da8506/mypy-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f995e511de847791c3b11ed90084a7a0aafdc074ab88c5a9711622fe4751138c", size = 11120432 }, { url = "https://files.pythonhosted.org/packages/b6/9e/47e450fd39078d9c02d620545b2cb37993a8a8bdf7db3652ace2f80521ca/mypy-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d64169ec3b8461311f8ce2fd2eb5d33e2d0f2c7b49116259c51d0d96edee48d1", size = 10279515 }, { url = "https://files.pythonhosted.org/packages/01/b5/6c8d33bd0f851a7692a8bfe4ee75eb82b6983a3cf39e5e32a5d2a723f0c1/mypy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba24549de7b89b6381b91fbc068d798192b1b5201987070319889e93038967a8", size = 12025791 }, { url = "https://files.pythonhosted.org/packages/f0/4c/e10e2c46ea37cab5c471d0ddaaa9a434dc1d28650078ac1b56c2d7b9b2e4/mypy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:183cf0a45457d28ff9d758730cd0210419ac27d4d3f285beda038c9083363b1f", size = 12749203 }, { url = "https://files.pythonhosted.org/packages/88/55/beacb0c69beab2153a0f57671ec07861d27d735a0faff135a494cd4f5020/mypy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2a0ecc86378f45347f586e4163d1769dd81c5a223d577fe351f26b179e148b1", size = 12885900 }, { url = "https://files.pythonhosted.org/packages/a2/75/8c93ff7f315c4d086a2dfcde02f713004357d70a163eddb6c56a6a5eff40/mypy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:ad3301ebebec9e8ee7135d8e3109ca76c23752bac1e717bc84cd3836b4bf3eae", size = 9777869 }, { url = "https://files.pythonhosted.org/packages/43/1b/b38c079609bb4627905b74fc6a49849835acf68547ac33d8ceb707de5f52/mypy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30ff5ef8519bbc2e18b3b54521ec319513a26f1bba19a7582e7b1f58a6e69f14", size = 11266668 }, { url = "https://files.pythonhosted.org/packages/6b/75/2ed0d2964c1ffc9971c729f7a544e9cd34b2cdabbe2d11afd148d7838aa2/mypy-1.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb9f255c18052343c70234907e2e532bc7e55a62565d64536dbc7706a20b78b9", size = 10254060 }, { url = "https://files.pythonhosted.org/packages/a1/5f/7b8051552d4da3c51bbe8fcafffd76a6823779101a2b198d80886cd8f08e/mypy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b4e3413e0bddea671012b063e27591b953d653209e7a4fa5e48759cda77ca11", size = 11933167 }, { url = "https://files.pythonhosted.org/packages/04/90/f53971d3ac39d8b68bbaab9a4c6c58c8caa4d5fd3d587d16f5927eeeabe1/mypy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:553c293b1fbdebb6c3c4030589dab9fafb6dfa768995a453d8a5d3b23784af2e", size = 12864341 }, { url = "https://files.pythonhosted.org/packages/03/d2/8bc0aeaaf2e88c977db41583559319f1821c069e943ada2701e86d0430b7/mypy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fad79bfe3b65fe6a1efaed97b445c3d37f7be9fdc348bdb2d7cac75579607c89", size = 12972991 }, { url = "https://files.pythonhosted.org/packages/6f/17/07815114b903b49b0f2cf7499f1c130e5aa459411596668267535fe9243c/mypy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fa2220e54d2946e94ab6dbb3ba0a992795bd68b16dc852db33028df2b00191b", size = 9879016 }, { url = "https://files.pythonhosted.org/packages/9e/15/bb6a686901f59222275ab228453de741185f9d54fecbaacec041679496c6/mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255", size = 11252097 }, { url = "https://files.pythonhosted.org/packages/f8/b3/8b0f74dfd072c802b7fa368829defdf3ee1566ba74c32a2cb2403f68024c/mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34", size = 10239728 }, { url = "https://files.pythonhosted.org/packages/c5/9b/4fd95ab20c52bb5b8c03cc49169be5905d931de17edfe4d9d2986800b52e/mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a", size = 11924965 }, { url = "https://files.pythonhosted.org/packages/56/9d/4a236b9c57f5d8f08ed346914b3f091a62dd7e19336b2b2a0d85485f82ff/mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9", size = 12867660 }, { url = "https://files.pythonhosted.org/packages/40/88/a61a5497e2f68d9027de2bb139c7bb9abaeb1be1584649fa9d807f80a338/mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd", size = 12969198 }, { url = "https://files.pythonhosted.org/packages/54/da/3d6fc5d92d324701b0c23fb413c853892bfe0e1dbe06c9138037d459756b/mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107", size = 9885276 }, { url = "https://files.pythonhosted.org/packages/39/02/1817328c1372be57c16148ce7d2bfcfa4a796bedaed897381b1aad9b267c/mypy-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7084fb8f1128c76cd9cf68fe5971b37072598e7c31b2f9f95586b65c741a9d31", size = 11143050 }, { url = "https://files.pythonhosted.org/packages/b9/07/99db9a95ece5e58eee1dd87ca456a7e7b5ced6798fd78182c59c35a7587b/mypy-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8f845a00b4f420f693f870eaee5f3e2692fa84cc8514496114649cfa8fd5e2c6", size = 10321087 }, { url = "https://files.pythonhosted.org/packages/9a/eb/85ea6086227b84bce79b3baf7f465b4732e0785830726ce4a51528173b71/mypy-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44bf464499f0e3a2d14d58b54674dee25c031703b2ffc35064bd0df2e0fac319", size = 12066766 }, { url = "https://files.pythonhosted.org/packages/4b/bb/f01bebf76811475d66359c259eabe40766d2f8ac8b8250d4e224bb6df379/mypy-1.14.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c99f27732c0b7dc847adb21c9d47ce57eb48fa33a17bc6d7d5c5e9f9e7ae5bac", size = 12787111 }, { url = "https://files.pythonhosted.org/packages/2f/c9/84837ff891edcb6dcc3c27d85ea52aab0c4a34740ff5f0ccc0eb87c56139/mypy-1.14.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:bce23c7377b43602baa0bd22ea3265c49b9ff0b76eb315d6c34721af4cdf1d9b", size = 12974331 }, { url = "https://files.pythonhosted.org/packages/84/5f/901e18464e6a13f8949b4909535be3fa7f823291b8ab4e4b36cfe57d6769/mypy-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:8edc07eeade7ebc771ff9cf6b211b9a7d93687ff892150cb5692e4f4272b0837", size = 9763210 }, { url = "https://files.pythonhosted.org/packages/ca/1f/186d133ae2514633f8558e78cd658070ba686c0e9275c5a5c24a1e1f0d67/mypy-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3888a1816d69f7ab92092f785a462944b3ca16d7c470d564165fe703b0970c35", size = 11200493 }, { url = "https://files.pythonhosted.org/packages/af/fc/4842485d034e38a4646cccd1369f6b1ccd7bc86989c52770d75d719a9941/mypy-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46c756a444117c43ee984bd055db99e498bc613a70bbbc120272bd13ca579fbc", size = 10357702 }, { url = "https://files.pythonhosted.org/packages/b4/e6/457b83f2d701e23869cfec013a48a12638f75b9d37612a9ddf99072c1051/mypy-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27fc248022907e72abfd8e22ab1f10e903915ff69961174784a3900a8cba9ad9", size = 12091104 }, { url = "https://files.pythonhosted.org/packages/f1/bf/76a569158db678fee59f4fd30b8e7a0d75bcbaeef49edd882a0d63af6d66/mypy-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:499d6a72fb7e5de92218db961f1a66d5f11783f9ae549d214617edab5d4dbdbb", size = 12830167 }, { url = "https://files.pythonhosted.org/packages/43/bc/0bc6b694b3103de9fed61867f1c8bd33336b913d16831431e7cb48ef1c92/mypy-1.14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57961db9795eb566dc1d1b4e9139ebc4c6b0cb6e7254ecde69d1552bf7613f60", size = 13013834 }, { url = "https://files.pythonhosted.org/packages/b0/79/5f5ec47849b6df1e6943d5fd8e6632fbfc04b4fd4acfa5a5a9535d11b4e2/mypy-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:07ba89fdcc9451f2ebb02853deb6aaaa3d2239a236669a63ab3801bbf923ef5c", size = 9781231 }, { url = "https://files.pythonhosted.org/packages/a0/b5/32dd67b69a16d088e533962e5044e51004176a9952419de0370cdaead0f8/mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1", size = 2752905 }, ] [[package]] name = "mypy-extensions" version = "1.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } wheels = [ { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, ] [[package]] name = "packaging" version = "24.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } wheels = [ { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, ] [[package]] name = "pluggy" version = "1.5.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } wheels = [ { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, ] [[package]] name = "pyclipper" version = "1.3.0.post6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4a/b2/550fe500e49c464d73fabcb8cb04d47e4885d6ca4cfc1f5b0a125a95b19a/pyclipper-1.3.0.post6.tar.gz", hash = "sha256:42bff0102fa7a7f2abdd795a2594654d62b786d0c6cd67b72d469114fdeb608c", size = 165909 } wheels = [ { url = "https://files.pythonhosted.org/packages/b5/34/0dca299fe41e9a92e78735502fed5238a4ac734755e624488df9b2eeec46/pyclipper-1.3.0.post6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fa0f5e78cfa8262277bb3d0225537b3c2a90ef68fd90a229d5d24cf49955dcf4", size = 269504 }, { url = "https://files.pythonhosted.org/packages/8a/5b/81528b08134b3c2abdfae821e1eff975c0703802d41974b02dfb2e101c55/pyclipper-1.3.0.post6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a01f182d8938c1dc515e8508ed2442f7eebd2c25c7d5cb29281f583c1a8008a4", size = 142599 }, { url = "https://files.pythonhosted.org/packages/84/a4/3e304f6c0d000382cd54d4a1e5f0d8fc28e1ae97413a2ec1016a7b840319/pyclipper-1.3.0.post6-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:640f20975727994d4abacd07396f564e9e5665ba5cb66ceb36b300c281f84fa4", size = 912209 }, { url = "https://files.pythonhosted.org/packages/f5/6a/28ec55cc3f972368b211fca017e081cf5a71009d1b8ec3559767cda5b289/pyclipper-1.3.0.post6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a63002f6bb0f1efa87c0b81634cbb571066f237067e23707dabf746306c92ba5", size = 929511 }, { url = "https://files.pythonhosted.org/packages/c4/56/c326f3454c5f30a31f58a5c3154d891fce58ad73ccbf1d3f4aacfcbd344d/pyclipper-1.3.0.post6-cp310-cp310-win32.whl", hash = "sha256:106b8622cd9fb07d80cbf9b1d752334c55839203bae962376a8c59087788af26", size = 100126 }, { url = "https://files.pythonhosted.org/packages/f8/e6/f8239af6346848b20a3448c554782fe59298ab06c1d040490242dc7e3c26/pyclipper-1.3.0.post6-cp310-cp310-win_amd64.whl", hash = "sha256:9699e98862dadefd0bea2360c31fa61ca553c660cbf6fb44993acde1b959f58f", size = 110470 }, { url = "https://files.pythonhosted.org/packages/50/a9/66ca5f252dcac93ca076698591b838ba17f9729591edf4b74fef7fbe1414/pyclipper-1.3.0.post6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4247e7c44b34c87acbf38f99d48fb1acaf5da4a2cf4dcd601a9b24d431be4ef", size = 270930 }, { url = "https://files.pythonhosted.org/packages/59/fe/2ab5818b3504e179086e54a37ecc245525d069267b8c31b18ec3d0830cbf/pyclipper-1.3.0.post6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:851b3e58106c62a5534a1201295fe20c21714dee2eda68081b37ddb0367e6caa", size = 143411 }, { url = "https://files.pythonhosted.org/packages/09/f7/b58794f643e033a6d14da7c70f517315c3072f3c5fccdf4232fa8c8090c1/pyclipper-1.3.0.post6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16cc1705a915896d2aff52131c427df02265631279eac849ebda766432714cc0", size = 951754 }, { url = "https://files.pythonhosted.org/packages/c1/77/846a21957cd4ed266c36705ee340beaa923eb57d2bba013cfd7a5c417cfd/pyclipper-1.3.0.post6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace1f0753cf71c5c5f6488b8feef5dd0fa8b976ad86b24bb51f708f513df4aac", size = 969608 }, { url = "https://files.pythonhosted.org/packages/c9/2b/580703daa6606d160caf596522d4cfdf62ae619b062a7ce6f905821a57e8/pyclipper-1.3.0.post6-cp311-cp311-win32.whl", hash = "sha256:dbc828641667142751b1127fd5c4291663490cf05689c85be4c5bcc89aaa236a", size = 100227 }, { url = "https://files.pythonhosted.org/packages/17/4b/a4cda18e8556d913ff75052585eb0d658500596b5f97fe8401d05123d47b/pyclipper-1.3.0.post6-cp311-cp311-win_amd64.whl", hash = "sha256:1c03f1ae43b18ee07730c3c774cc3cf88a10c12a4b097239b33365ec24a0a14a", size = 110442 }, { url = "https://files.pythonhosted.org/packages/fc/c8/197d9a1d8354922d24d11d22fb2e0cc1ebc182f8a30496b7ddbe89467ce1/pyclipper-1.3.0.post6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:6363b9d79ba1b5d8f32d1623e797c1e9f994600943402e68d5266067bdde173e", size = 270487 }, { url = "https://files.pythonhosted.org/packages/8e/8e/eb14eadf054494ad81446e21c4ea163b941747610b0eb9051644395f567e/pyclipper-1.3.0.post6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:32cd7fb9c1c893eb87f82a072dbb5e26224ea7cebbad9dc306d67e1ac62dd229", size = 143469 }, { url = "https://files.pythonhosted.org/packages/cf/e5/6c4a8df6e904c133bb4c5309d211d31c751db60cbd36a7250c02b05494a1/pyclipper-1.3.0.post6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3aab10e3c10ed8fa60c608fb87c040089b83325c937f98f06450cf9fcfdaf1d", size = 944206 }, { url = "https://files.pythonhosted.org/packages/76/65/cb014acc41cd5bf6bbfa4671c7faffffb9cee01706642c2dec70c5209ac8/pyclipper-1.3.0.post6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58eae2ff92a8cae1331568df076c4c5775bf946afab0068b217f0cf8e188eb3c", size = 963797 }, { url = "https://files.pythonhosted.org/packages/80/ec/b40cd81ab7598984167508a5369a2fa31a09fe3b3e3d0b73aa50e06d4b3f/pyclipper-1.3.0.post6-cp312-cp312-win32.whl", hash = "sha256:793b0aa54b914257aa7dc76b793dd4dcfb3c84011d48df7e41ba02b571616eaf", size = 99456 }, { url = "https://files.pythonhosted.org/packages/24/3a/7d6292e3c94fb6b872d8d7e80d909dc527ee6b0af73b753c63fdde65a7da/pyclipper-1.3.0.post6-cp312-cp312-win_amd64.whl", hash = "sha256:d3f9da96f83b8892504923beb21a481cd4516c19be1d39eb57a92ef1c9a29548", size = 110278 }, { url = "https://files.pythonhosted.org/packages/8c/b3/75232906bd13f869600d23bdb8fe6903cc899fa7e96981ae4c9b7d9c409e/pyclipper-1.3.0.post6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f129284d2c7bcd213d11c0f35e1ae506a1144ce4954e9d1734d63b120b0a1b58", size = 268254 }, { url = "https://files.pythonhosted.org/packages/0b/db/35843050a3dd7586781497a21ca6c8d48111afb66061cb40c3d3c288596d/pyclipper-1.3.0.post6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:188fbfd1d30d02247f92c25ce856f5f3c75d841251f43367dbcf10935bc48f38", size = 142204 }, { url = "https://files.pythonhosted.org/packages/7c/d7/1faa0ff35caa02cb32cb0583688cded3f38788f33e02bfe6461fbcc1bee1/pyclipper-1.3.0.post6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6d129d0c2587f2f5904d201a4021f859afbb45fada4261c9fdedb2205b09d23", size = 943835 }, { url = "https://files.pythonhosted.org/packages/31/10/c0bf140bee2844e2c0617fdcc8a4e8daf98e71710046b06034e6f1963404/pyclipper-1.3.0.post6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c9c80b5c46eef38ba3f12dd818dc87f5f2a0853ba914b6f91b133232315f526", size = 962510 }, { url = "https://files.pythonhosted.org/packages/85/6f/8c6afc49b51b1bf16d5903ecd5aee657cf88f52c83cb5fabf771deeba728/pyclipper-1.3.0.post6-cp313-cp313-win32.whl", hash = "sha256:b15113ec4fc423b58e9ae80aa95cf5a0802f02d8f02a98a46af3d7d66ff0cc0e", size = 98836 }, { url = "https://files.pythonhosted.org/packages/d5/19/9ff4551b42f2068686c50c0d199072fa67aee57fc5cf86770cacf71efda3/pyclipper-1.3.0.post6-cp313-cp313-win_amd64.whl", hash = "sha256:e5ff68fa770ac654c7974fc78792978796f068bd274e95930c0691c31e192889", size = 109672 }, { url = "https://files.pythonhosted.org/packages/04/c6/7989c62e7d5e3fc25ecbc3ea8b243c44e8aa676c3e7c5a5f9bb3216e6d57/pyclipper-1.3.0.post6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cf0a535cfa02b207435928e991c60389671fe1ea1dfae79170973f82f52335b2", size = 271286 }, { url = "https://files.pythonhosted.org/packages/de/d0/1f242d9026cb1f0c27ef799e7ce78e9c26233433b8e174dbd3cd719b7b54/pyclipper-1.3.0.post6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:48dd55fbd55f63902cad511432ec332368cbbbc1dd2110c0c6c1e9edd735713a", size = 143498 }, { url = "https://files.pythonhosted.org/packages/23/50/bad0e215290354c1e2b2e3b49dbc7300f0bbbc3dea0e2f2bce68ee5d5136/pyclipper-1.3.0.post6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05ae2ea878fdfa31dd375326f6191b03de98a9602cc9c2b6d4ff960b20a974c", size = 933307 }, { url = "https://files.pythonhosted.org/packages/8e/b3/3cd2c225df1ceeb3571adfd732b7e21744c42e556d3c02000c4e958a7dba/pyclipper-1.3.0.post6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:903176952a159c4195b8be55e597978e24804c838c7a9b12024c39704d341f72", size = 687788 }, { url = "https://files.pythonhosted.org/packages/5e/b9/f51338ae810af48675572beb95f9f79c36b51aab1cb266be8b3e7969ffc9/pyclipper-1.3.0.post6-cp38-cp38-win32.whl", hash = "sha256:fb1e52cf4ee0a9fa8b2254ed589cc51b0c989efc58fa8804289aca94a21253f7", size = 100519 }, { url = "https://files.pythonhosted.org/packages/ef/a3/79e776963d243a3b361adbcfb7e41badd46d3d5f278c46a7e72804052e1c/pyclipper-1.3.0.post6-cp38-cp38-win_amd64.whl", hash = "sha256:9cbdc517e75e647aa9bf6e356b3a3d2e3af344f82af38e36031eb46ba0ab5425", size = 110952 }, { url = "https://files.pythonhosted.org/packages/6d/05/58091c351d5dceb08f05d8c5bee56969138366ceaec37c695b0455b2c1ee/pyclipper-1.3.0.post6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:383f3433b968f2e4b0843f338c1f63b85392b6e1d936de722e8c5d4f577dbff5", size = 270559 }, { url = "https://files.pythonhosted.org/packages/bc/44/289bcef04c11471d19db83c9c2dcb41e597aff050e38dc80a7a142343b90/pyclipper-1.3.0.post6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cf5ca2b9358d30a395ac6e14b3154a9fd1f9b557ad7153ea15cf697e88d07ce1", size = 143146 }, { url = "https://files.pythonhosted.org/packages/ee/ad/7acc6f62084feaa88507f2c4947f16c95d16dd6b3edff27990d2e93b442d/pyclipper-1.3.0.post6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3404dfcb3415eee863564b5f49be28a8c7fb99ad5e31c986bcc33c8d47d97df7", size = 931298 }, { url = "https://files.pythonhosted.org/packages/27/83/6b9598ce011d5e61af317baed9d192ece8fee6986f7424239d94f786124f/pyclipper-1.3.0.post6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:aa0e7268f8ceba218964bc3a482a5e9d32e352e8c3538b03f69a6b3db979078d", size = 674167 }, { url = "https://files.pythonhosted.org/packages/4f/75/4a5bbdeeca32d3e12252e9a458c8fc34b8878dd8de56b53b9d7ee33e5596/pyclipper-1.3.0.post6-cp39-cp39-win32.whl", hash = "sha256:47a214f201ff930595a30649c2a063f78baa3a8f52e1f38da19f7930c90ed80c", size = 100409 }, { url = "https://files.pythonhosted.org/packages/df/ec/46f6621472bbf1f415969985dcd691e674dc8b876cb76524f6ac2eea51b6/pyclipper-1.3.0.post6-cp39-cp39-win_amd64.whl", hash = "sha256:28bb590ae79e6beb15794eaee12b6f1d769589572d33e494faf5aa3b1f31b9fa", size = 110777 }, { url = "https://files.pythonhosted.org/packages/d3/40/440543e4b19e540ed0e5ffc1c29af495be78e106cd5c8f3034d58fae78be/pyclipper-1.3.0.post6-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3d58202de8b8da4d1559afbda4e90a8c260a5373672b6d7bc5448c4614385144", size = 138084 }, { url = "https://files.pythonhosted.org/packages/5d/1c/3ff418815d1788058c5b24a9f33998765de23bec62705f958c33b6bdc11e/pyclipper-1.3.0.post6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2cd8600bd16d209d5d45a33b45c278e1cc8bedc169af1a1f2187b581c521395", size = 135275 }, ] [[package]] name = "pytest" version = "8.3.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } wheels = [ { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, ] [[package]] name = "pytest-cov" version = "5.0.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.9'", ] dependencies = [ { name = "coverage", version = "7.6.1", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version < '3.9'" }, { name = "pytest", marker = "python_full_version < '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/74/67/00efc8d11b630c56f15f4ad9c7f9223f1e5ec275aaae3fa9118c6a223ad2/pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857", size = 63042 } wheels = [ { url = "https://files.pythonhosted.org/packages/78/3a/af5b4fa5961d9a1e6237b530eb87dd04aea6eb83da09d2a4073d81b54ccf/pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", size = 21990 }, ] [[package]] name = "pytest-cov" version = "6.0.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.9'", ] dependencies = [ { name = "coverage", version = "7.6.10", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.9'" }, { name = "pytest", marker = "python_full_version >= '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 } wheels = [ { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 }, ] [[package]] name = "ruff" version = "0.9.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/80/63/77ecca9d21177600f551d1c58ab0e5a0b260940ea7312195bd2a4798f8a8/ruff-0.9.2.tar.gz", hash = "sha256:b5eceb334d55fae5f316f783437392642ae18e16dcf4f1858d55d3c2a0f8f5d0", size = 3553799 } wheels = [ { url = "https://files.pythonhosted.org/packages/af/b9/0e168e4e7fb3af851f739e8f07889b91d1a33a30fca8c29fa3149d6b03ec/ruff-0.9.2-py3-none-linux_armv6l.whl", hash = "sha256:80605a039ba1454d002b32139e4970becf84b5fee3a3c3bf1c2af6f61a784347", size = 11652408 }, { url = "https://files.pythonhosted.org/packages/2c/22/08ede5db17cf701372a461d1cb8fdde037da1d4fa622b69ac21960e6237e/ruff-0.9.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b9aab82bb20afd5f596527045c01e6ae25a718ff1784cb92947bff1f83068b00", size = 11587553 }, { url = "https://files.pythonhosted.org/packages/42/05/dedfc70f0bf010230229e33dec6e7b2235b2a1b8cbb2a991c710743e343f/ruff-0.9.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fbd337bac1cfa96be615f6efcd4bc4d077edbc127ef30e2b8ba2a27e18c054d4", size = 11020755 }, { url = "https://files.pythonhosted.org/packages/df/9b/65d87ad9b2e3def67342830bd1af98803af731243da1255537ddb8f22209/ruff-0.9.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82b35259b0cbf8daa22a498018e300b9bb0174c2bbb7bcba593935158a78054d", size = 11826502 }, { url = "https://files.pythonhosted.org/packages/93/02/f2239f56786479e1a89c3da9bc9391120057fc6f4a8266a5b091314e72ce/ruff-0.9.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b6a9701d1e371bf41dca22015c3f89769da7576884d2add7317ec1ec8cb9c3c", size = 11390562 }, { url = "https://files.pythonhosted.org/packages/c9/37/d3a854dba9931f8cb1b2a19509bfe59e00875f48ade632e95aefcb7a0aee/ruff-0.9.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cc53e68b3c5ae41e8faf83a3b89f4a5d7b2cb666dff4b366bb86ed2a85b481f", size = 12548968 }, { url = "https://files.pythonhosted.org/packages/fa/c3/c7b812bb256c7a1d5553433e95980934ffa85396d332401f6b391d3c4569/ruff-0.9.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8efd9da7a1ee314b910da155ca7e8953094a7c10d0c0a39bfde3fcfd2a015684", size = 13187155 }, { url = "https://files.pythonhosted.org/packages/bd/5a/3c7f9696a7875522b66aa9bba9e326e4e5894b4366bd1dc32aa6791cb1ff/ruff-0.9.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3292c5a22ea9a5f9a185e2d131dc7f98f8534a32fb6d2ee7b9944569239c648d", size = 12704674 }, { url = "https://files.pythonhosted.org/packages/be/d6/d908762257a96ce5912187ae9ae86792e677ca4f3dc973b71e7508ff6282/ruff-0.9.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a605fdcf6e8b2d39f9436d343d1f0ff70c365a1e681546de0104bef81ce88df", size = 14529328 }, { url = "https://files.pythonhosted.org/packages/2d/c2/049f1e6755d12d9cd8823242fa105968f34ee4c669d04cac8cea51a50407/ruff-0.9.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c547f7f256aa366834829a08375c297fa63386cbe5f1459efaf174086b564247", size = 12385955 }, { url = "https://files.pythonhosted.org/packages/91/5a/a9bdb50e39810bd9627074e42743b00e6dc4009d42ae9f9351bc3dbc28e7/ruff-0.9.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d18bba3d3353ed916e882521bc3e0af403949dbada344c20c16ea78f47af965e", size = 11810149 }, { url = "https://files.pythonhosted.org/packages/e5/fd/57df1a0543182f79a1236e82a79c68ce210efb00e97c30657d5bdb12b478/ruff-0.9.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b338edc4610142355ccf6b87bd356729b62bf1bc152a2fad5b0c7dc04af77bfe", size = 11479141 }, { url = "https://files.pythonhosted.org/packages/dc/16/bc3fd1d38974f6775fc152a0554f8c210ff80f2764b43777163c3c45d61b/ruff-0.9.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:492a5e44ad9b22a0ea98cf72e40305cbdaf27fac0d927f8bc9e1df316dcc96eb", size = 12014073 }, { url = "https://files.pythonhosted.org/packages/47/6b/e4ca048a8f2047eb652e1e8c755f384d1b7944f69ed69066a37acd4118b0/ruff-0.9.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:af1e9e9fe7b1f767264d26b1075ac4ad831c7db976911fa362d09b2d0356426a", size = 12435758 }, { url = "https://files.pythonhosted.org/packages/c2/40/4d3d6c979c67ba24cf183d29f706051a53c36d78358036a9cd21421582ab/ruff-0.9.2-py3-none-win32.whl", hash = "sha256:71cbe22e178c5da20e1514e1e01029c73dc09288a8028a5d3446e6bba87a5145", size = 9796916 }, { url = "https://files.pythonhosted.org/packages/c3/ef/7f548752bdb6867e6939489c87fe4da489ab36191525fadc5cede2a6e8e2/ruff-0.9.2-py3-none-win_amd64.whl", hash = "sha256:c5e1d6abc798419cf46eed03f54f2e0c3adb1ad4b801119dedf23fcaf69b55b5", size = 10773080 }, { url = "https://files.pythonhosted.org/packages/0e/4e/33df635528292bd2d18404e4daabcd74ca8a9853b2e1df85ed3d32d24362/ruff-0.9.2-py3-none-win_arm64.whl", hash = "sha256:a1b63fa24149918f8b37cef2ee6fff81f24f0d74b6f0bdc37bc3e1f2143e41c6", size = 10001738 }, ] [[package]] name = "setuptools" version = "75.3.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/ed/22/a438e0caa4576f8c383fa4d35f1cc01655a46c75be358960d815bfbb12bd/setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686", size = 1351577 } wheels = [ { url = "https://files.pythonhosted.org/packages/90/12/282ee9bce8b58130cb762fbc9beabd531549952cac11fc56add11dcb7ea0/setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd", size = 1251070 }, ] [[package]] name = "setuptools" version = "75.8.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.9'", ] sdist = { url = "https://files.pythonhosted.org/packages/92/ec/089608b791d210aec4e7f97488e67ab0d33add3efccb83a056cbafe3a2a6/setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6", size = 1343222 } wheels = [ { url = "https://files.pythonhosted.org/packages/69/8a/b9dc7678803429e4a3bc9ba462fa3dd9066824d3c607490235c6a796be5a/setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3", size = 1228782 }, ] [[package]] name = "six" version = "1.17.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, ] [[package]] name = "statmake" source = { editable = "." } dependencies = [ { name = "attrs" }, { name = "cattrs" }, { name = "fonttools", extra = ["ufo"] }, ] [package.dev-dependencies] dev = [ { name = "mypy" }, { name = "pytest" }, { name = "pytest-cov", version = "5.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "pytest-cov", version = "6.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, { name = "ruff" }, { name = "ufo2ft" }, { name = "ufolib2" }, ] [package.metadata] requires-dist = [ { name = "attrs", specifier = ">=21.3" }, { name = "cattrs", specifier = ">=22.2" }, { name = "fonttools", extras = ["ufo"], specifier = ">=4.11" }, ] [package.metadata.requires-dev] dev = [ { name = "mypy" }, { name = "pytest", specifier = ">=8" }, { name = "pytest-cov", specifier = ">=5" }, { name = "ruff", specifier = ">=0.9" }, { name = "ufo2ft", specifier = ">=2.7" }, { name = "ufolib2", specifier = ">=0.4" }, ] [[package]] name = "tomli" version = "2.2.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } wheels = [ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, ] [[package]] name = "typing-extensions" version = "4.12.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } wheels = [ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, ] [[package]] name = "ufo2ft" version = "3.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "booleanoperations" }, { name = "cffsubr" }, { name = "fontmath" }, { name = "fonttools", extra = ["ufo"] }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/82/da6aa67b88c5a435352d7ee903b739e7943cdd16df3afb57dbb9469e0d58/ufo2ft-3.4.0.tar.gz", hash = "sha256:0cf7dbc723c8f1d5703f1381232e790b75cdbd666a43565debf2fc96209d6f28", size = 427885 } wheels = [ { url = "https://files.pythonhosted.org/packages/c8/d3/955dbb1413271d3c880763b7d49121d11c510cd94e07f5fc260fbd521afa/ufo2ft-3.4.0-py2.py3-none-any.whl", hash = "sha256:51dd110446a536e0d508084f11b8608235d706db8b21e782e7b544c0a5a861a7", size = 160787 }, ] [[package]] name = "ufolib2" version = "0.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "fonttools", extra = ["ufo"] }, ] sdist = { url = "https://files.pythonhosted.org/packages/fb/4a/45e392757bd28148d954c7418b99afbed4b45c334b52f42daaceed885aa5/ufolib2-0.17.1.tar.gz", hash = "sha256:f6ab3171ff20615bb81c888faae1d871566bd14de6bdc94cc8f3971f6377bbd0", size = 97354 } wheels = [ { url = "https://files.pythonhosted.org/packages/38/b5/52a996e4dade25b4659542ff7f727e05fc32d59082bfb15389a399f4484e/ufoLib2-0.17.1-py3-none-any.whl", hash = "sha256:aa3a03dcb51cde7b9696d496ca603bb13d6633e295cbd14a3f7ff293df23bc2a", size = 52825 }, ]