1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
#!/usr/bin/env python3
#
# sdist.py
"""
Utilities for working with source distributions.
.. versionadded:: 0.9.0
.. autosummary::
~shippinglabel.sdist.NotAnSdistError
~shippinglabel.sdist.ParsedSdistFilename
~shippinglabel.sdist.parse_sdist_filename
"""
#
# 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.
#
# Based on wheel-filename
# https://github.com/jwodder/wheel-filename
# Copyright (c) 2020 John Thorvald Wodder II
# MIT Licensed
# stdlib
import os
import re
from typing import NamedTuple
# 3rd party
from domdf_python_tools.paths import PathPlus
from domdf_python_tools.typing import PathLike
from packaging.utils import InvalidSdistFilename
__all__ = ["NotAnSdistError", "ParsedSdistFilename", "parse_sdist_filename"]
class NotAnSdistError(ValueError):
"""
Raised when something other than a source distribution is passed to :func:`~.parse_sdist_filename`.
"""
filename: str
def __init__(self, filename: PathLike, msg: str = '') -> None:
#: The invalid filename
self.filename = str(filename)
super().__init__(msg)
def __str__(self) -> str:
return super().__str__().format(repr(self.filename))
class ParsedSdistFilename(NamedTuple):
"""
Represents a parsed sdist filename.
:param project: The name of the project.
"""
#: The name of the project. The case is the same as in the filename.
project: str
#: The version number of the project.
version: str
#: The file extension of the sdist, e.g. ``.tar.gz``.
extension: str
def __str__(self) -> str:
return f'{self.project}-{self.version}{self.extension}'
SDIST_FILENAME_CRGX = re.compile(
r'(?P<project>[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?(-stubs)?)'
r'-(?P<version>[A-Za-z0-9_.!+]+)'
r'(?P<extension>.tar.gz|.tar.bz2|.zip)'
)
def parse_sdist_filename(filename: PathLike) -> ParsedSdistFilename:
"""
Parse a sdist filename into its components.
:param filename: An sdist path or filename.
:raises:
* :exc:`packaging.utils.InvalidSdistFilename` if the filename is invalid.
.. versionchanged:: 1.0.0 Previously raised :exc:`wheel_filename.InvalidFilenameError`
* :exc:`shippinglabel.sdist.NotAnSdistError` if the file is not an sdist.
:rtype:
.. seealso:: :func:`packaging.utils.parse_sdist_filename`
"""
filename = PathPlus(filename)
if filename.suffix == ".whl":
raise NotAnSdistError(filename, "{} is a wheel.")
basename = os.path.basename(filename)
m = SDIST_FILENAME_CRGX.fullmatch(basename)
if not m:
raise InvalidSdistFilename(f"Invalid sdist filename: {basename!r}")
return ParsedSdistFilename(**m.groupdict())
|