Source code for dist_meta.wheel

#!/usr/bin/env python3
#
#  wheel.py
"""
Parse and create ``*dist-info/WHEEL`` files.
"""
#
#  Copyright © 2021 Dominic Davis-Foster <dominic@davis-foster.co.uk>
#
#  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.
#

# stdlib
from typing import Any, List, Mapping, Optional, Tuple, Union

# 3rd party
from domdf_python_tools.paths import PathPlus
from domdf_python_tools.typing import PathLike
from domdf_python_tools.utils import divide, strtobool

# this package
from dist_meta.metadata import MetadataEmitter, MissingFieldError
from dist_meta.metadata_mapping import MetadataMapping

__all__ = ("dump", "dumps", "load", "loads", "parse_generator_string")


[docs]def loads(rawtext: str) -> MetadataMapping: """ Parse a ``WHEEL`` file from the given string. :param rawtext: :returns: A mapping of the metadata fields, and the long description """ file_content: List[str] = rawtext.splitlines() file_content.reverse() fields: MetadataMapping = MetadataMapping() while file_content: line = file_content.pop() if line.strip(): field_name, field_value = divide(line, ':') fields[field_name] = field_value.lstrip() # pylint: disable=loop-invariant-statement if "Wheel-Version" not in fields: raise MissingFieldError(f"No 'Wheel-Version' field was provided.") return fields
[docs]def load(filename: PathLike) -> MetadataMapping: """ Parse a ``WHEEL`` file from the given file. :param filename: :returns: A mapping of the metadata fields, and the long description """ filename = PathPlus(filename) return loads(filename.read_text())
[docs]def dumps(fields: Union[Mapping[str, Any], MetadataMapping]) -> str: """ Construct a ``WHEEL`` file from the given fields. :param fields: May be a conventional mapping, with ``Root-Is-Purelib`` as a boolean and ``Tag`` as a list of strings. """ output = MetadataEmitter(fields) # type: ignore[arg-type] if "Wheel-Version" in fields: output.append(f"Wheel-Version: {float(fields['Wheel-Version'])}") else: raise MissingFieldError(f"No 'Wheel-Version' field was provided.") output.add_single("Generator") root_is_purelib = strtobool(fields.get("Root-Is-Purelib", False)) output.append(f"Root-Is-Purelib: {str(root_is_purelib).lower()}") if "Tag" in fields and isinstance(fields, MetadataMapping): output.add_multiple("Tag") elif "Tag" in fields: for value in fields["Tag"]: # pylint: disable=use-list-copy output.append(f"Tag: {value}") output.add_single("Build") return str(output)
[docs]def dump(fields: Union[Mapping[str, Any], MetadataMapping], filename: PathLike) -> int: """ Construct a ``WHEEL`` file from the given fields, and write it to ``filename``. :param fields: May be a conventional mapping, with ``Root-Is-Purelib`` as a boolean and ``Tag`` as a list of strings. :param filename: """ filename = PathPlus(filename) return filename.write_text(dumps(fields))
[docs]def parse_generator_string(generator: str) -> Tuple[str, Optional[str]]: """ Parse a generator string into its name and version. Common forms include: * ``name (version)`` * ``name version`` * ``name`` .. versionadded:: 0.6.0 :param generator: The raw generator string (the ``Generator`` field in ``WHEEL``). :return: A tuple of the generator name and its version. The version may be :py:obj:`None` if no version could be found. """ generator = generator.rstrip() if ' ' not in generator: return generator, None name, version = generator.split(' ', 1) version = version.lstrip('(').rstrip(')') return name, version