Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
__init__.py187 linesDownload Raw Back to licenses
1#######################################################################################2#3# Adapted from:4#  https://github.com/pypa/hatch/blob/5352e44/backend/src/hatchling/licenses/parse.py5#6# MIT License7#8# Copyright (c) 2017-present Ofek Lev <oss@ofek.dev>9#10# Permission is hereby granted, free of charge, to any person obtaining a copy of this11# software and associated documentation files (the "Software"), to deal in the Software12# without restriction, including without limitation the rights to use, copy, modify,13# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to14# permit persons to whom the Software is furnished to do so, subject to the following15# conditions:16#17# The above copyright notice and this permission notice shall be included in all copies18# or substantial portions of the Software.19#20# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,21# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A22# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT23# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF24# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE25# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.26#27#28# With additional allowance of arbitrary `LicenseRef-` identifiers, not just29# `LicenseRef-Public-Domain` and `LicenseRef-Proprietary`.30#31#######################################################################################32from __future__ import annotations33 34import re35from typing import NewType, cast36 37from ._spdx import EXCEPTIONS, LICENSES38 39__all__ = [40    "InvalidLicenseExpression",41    "NormalizedLicenseExpression",42    "canonicalize_license_expression",43]44 45 46# Simple __dir__ implementation since there are no public submodules47def __dir__() -> list[str]:48    return __all__49 50 51license_ref_allowed = re.compile("^[A-Za-z0-9.-]*$")52 53NormalizedLicenseExpression = NewType("NormalizedLicenseExpression", str)54"""55A :class:`typing.NewType` of :class:`str`, representing a normalized56License-Expression.57"""58 59 60class InvalidLicenseExpression(ValueError):61    """Raised when a license-expression string is invalid62 63    >>> from packaging.licenses import canonicalize_license_expression64    >>> canonicalize_license_expression("invalid")65    Traceback (most recent call last):66        ...67    packaging.licenses.InvalidLicenseExpression: Invalid license expression: 'invalid'68    """69 70 71def canonicalize_license_expression(72    raw_license_expression: str,73) -> NormalizedLicenseExpression:74    """75    This function takes a valid License-Expression, and returns the normalized76    form of it.77 78    The return type is typed as :class:`NormalizedLicenseExpression`. This79    allows type checkers to help require that a string has passed through this80    function before use.81 82    :param str raw_license_expression: The License-Expression to canonicalize.83    :raises InvalidLicenseExpression: If the License-Expression is invalid due to an84        invalid/unknown license identifier or invalid syntax.85 86    .. doctest::87 88        >>> from packaging.licenses import canonicalize_license_expression89        >>> canonicalize_license_expression("mit")90        'MIT'91        >>> canonicalize_license_expression("mit and (apache-2.0 or bsd-2-clause)")92        'MIT AND (Apache-2.0 OR BSD-2-Clause)'93        >>> canonicalize_license_expression("(mit")94        Traceback (most recent call last):95          ...96        InvalidLicenseExpression: Invalid license expression: '(mit'97        >>> canonicalize_license_expression("Use-it-after-midnight")98        Traceback (most recent call last):99          ...100        InvalidLicenseExpression: Unknown license: 'Use-it-after-midnight'101    """102    if not raw_license_expression:103        message = f"Invalid license expression: {raw_license_expression!r}"104        raise InvalidLicenseExpression(message)105 106    # Pad any parentheses so tokenization can be achieved by merely splitting on107    # whitespace.108    license_expression = raw_license_expression.replace("(", " ( ").replace(")", " ) ")109    licenseref_prefix = "LicenseRef-"110    license_refs = {111        ref.lower(): "LicenseRef-" + ref[len(licenseref_prefix) :]112        for ref in license_expression.split()113        if ref.lower().startswith(licenseref_prefix.lower())114    }115 116    # Normalize to lower case so we can look up licenses/exceptions117    # and so boolean operators are Python-compatible.118    license_expression = license_expression.lower()119 120    tokens = license_expression.split()121 122    # Rather than implementing a parenthesis/boolean logic parser, create an123    # expression that Python can parse. Everything that is not involved with the124    # grammar itself is replaced with the placeholder `False` and the resultant125    # expression should become a valid Python expression.126    python_tokens = []127    for token in tokens:128        if token not in {"or", "and", "with", "(", ")"}:129            python_tokens.append("False")130        elif token == "with":131            python_tokens.append("or")132        elif (133            token == "("134            and python_tokens135            and python_tokens[-1] not in {"or", "and", "("}136        ) or (token == ")" and python_tokens and python_tokens[-1] == "("):137            message = f"Invalid license expression: {raw_license_expression!r}"138            raise InvalidLicenseExpression(message)139        else:140            python_tokens.append(token)141 142    python_expression = " ".join(python_tokens)143    try:144        compile(python_expression, "", "eval")145    except SyntaxError:146        message = f"Invalid license expression: {raw_license_expression!r}"147        raise InvalidLicenseExpression(message) from None148 149    # Take a final pass to check for unknown licenses/exceptions.150    normalized_tokens = []151    for token in tokens:152        if token in {"or", "and", "with", "(", ")"}:153            normalized_tokens.append(token.upper())154            continue155 156        if normalized_tokens and normalized_tokens[-1] == "WITH":157            if token not in EXCEPTIONS:158                message = f"Unknown license exception: {token!r}"159                raise InvalidLicenseExpression(message)160 161            normalized_tokens.append(EXCEPTIONS[token]["id"])162        else:163            if token.endswith("+"):164                final_token = token[:-1]165                suffix = "+"166            else:167                final_token = token168                suffix = ""169 170            if final_token.startswith("licenseref-"):171                if not license_ref_allowed.match(final_token):172                    message = f"Invalid licenseref: {final_token!r}"173                    raise InvalidLicenseExpression(message)174                normalized_tokens.append(license_refs[final_token] + suffix)175            else:176                if final_token not in LICENSES:177                    message = f"Unknown license: {final_token!r}"178                    raise InvalidLicenseExpression(message)179                normalized_tokens.append(LICENSES[final_token]["id"] + suffix)180 181    normalized_expression = " ".join(normalized_tokens)182 183    return cast(184        "NormalizedLicenseExpression",185        normalized_expression.replace("( ", "(").replace(" )", ")"),186    )187 
codekingpro/portable-devtools · Team Ai