mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-03-12 04:35:40 -07:00
* Bump packaging from 24.1 to 24.2 Bumps [packaging](https://github.com/pypa/packaging) from 24.1 to 24.2. - [Release notes](https://github.com/pypa/packaging/releases) - [Changelog](https://github.com/pypa/packaging/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pypa/packaging/compare/24.1...24.2) --- updated-dependencies: - dependency-name: packaging dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Update packaging==24.2 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci]
146 lines
5.6 KiB
Python
146 lines
5.6 KiB
Python
#######################################################################################
|
|
#
|
|
# Adapted from:
|
|
# https://github.com/pypa/hatch/blob/5352e44/backend/src/hatchling/licenses/parse.py
|
|
#
|
|
# MIT License
|
|
#
|
|
# Copyright (c) 2017-present Ofek Lev <oss@ofek.dev>
|
|
#
|
|
# 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.
|
|
#
|
|
#
|
|
# With additional allowance of arbitrary `LicenseRef-` identifiers, not just
|
|
# `LicenseRef-Public-Domain` and `LicenseRef-Proprietary`.
|
|
#
|
|
#######################################################################################
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from typing import NewType, cast
|
|
|
|
from packaging.licenses._spdx import EXCEPTIONS, LICENSES
|
|
|
|
__all__ = [
|
|
"NormalizedLicenseExpression",
|
|
"InvalidLicenseExpression",
|
|
"canonicalize_license_expression",
|
|
]
|
|
|
|
license_ref_allowed = re.compile("^[A-Za-z0-9.-]*$")
|
|
|
|
NormalizedLicenseExpression = NewType("NormalizedLicenseExpression", str)
|
|
|
|
|
|
class InvalidLicenseExpression(ValueError):
|
|
"""Raised when a license-expression string is invalid
|
|
|
|
>>> canonicalize_license_expression("invalid")
|
|
Traceback (most recent call last):
|
|
...
|
|
packaging.licenses.InvalidLicenseExpression: Invalid license expression: 'invalid'
|
|
"""
|
|
|
|
|
|
def canonicalize_license_expression(
|
|
raw_license_expression: str,
|
|
) -> NormalizedLicenseExpression:
|
|
if not raw_license_expression:
|
|
message = f"Invalid license expression: {raw_license_expression!r}"
|
|
raise InvalidLicenseExpression(message)
|
|
|
|
# Pad any parentheses so tokenization can be achieved by merely splitting on
|
|
# whitespace.
|
|
license_expression = raw_license_expression.replace("(", " ( ").replace(")", " ) ")
|
|
licenseref_prefix = "LicenseRef-"
|
|
license_refs = {
|
|
ref.lower(): "LicenseRef-" + ref[len(licenseref_prefix) :]
|
|
for ref in license_expression.split()
|
|
if ref.lower().startswith(licenseref_prefix.lower())
|
|
}
|
|
|
|
# Normalize to lower case so we can look up licenses/exceptions
|
|
# and so boolean operators are Python-compatible.
|
|
license_expression = license_expression.lower()
|
|
|
|
tokens = license_expression.split()
|
|
|
|
# Rather than implementing boolean logic, we create an expression that Python can
|
|
# parse. Everything that is not involved with the grammar itself is treated as
|
|
# `False` and the expression should evaluate as such.
|
|
python_tokens = []
|
|
for token in tokens:
|
|
if token not in {"or", "and", "with", "(", ")"}:
|
|
python_tokens.append("False")
|
|
elif token == "with":
|
|
python_tokens.append("or")
|
|
elif token == "(" and python_tokens and python_tokens[-1] not in {"or", "and"}:
|
|
message = f"Invalid license expression: {raw_license_expression!r}"
|
|
raise InvalidLicenseExpression(message)
|
|
else:
|
|
python_tokens.append(token)
|
|
|
|
python_expression = " ".join(python_tokens)
|
|
try:
|
|
invalid = eval(python_expression, globals(), locals())
|
|
except Exception:
|
|
invalid = True
|
|
|
|
if invalid is not False:
|
|
message = f"Invalid license expression: {raw_license_expression!r}"
|
|
raise InvalidLicenseExpression(message) from None
|
|
|
|
# Take a final pass to check for unknown licenses/exceptions.
|
|
normalized_tokens = []
|
|
for token in tokens:
|
|
if token in {"or", "and", "with", "(", ")"}:
|
|
normalized_tokens.append(token.upper())
|
|
continue
|
|
|
|
if normalized_tokens and normalized_tokens[-1] == "WITH":
|
|
if token not in EXCEPTIONS:
|
|
message = f"Unknown license exception: {token!r}"
|
|
raise InvalidLicenseExpression(message)
|
|
|
|
normalized_tokens.append(EXCEPTIONS[token]["id"])
|
|
else:
|
|
if token.endswith("+"):
|
|
final_token = token[:-1]
|
|
suffix = "+"
|
|
else:
|
|
final_token = token
|
|
suffix = ""
|
|
|
|
if final_token.startswith("licenseref-"):
|
|
if not license_ref_allowed.match(final_token):
|
|
message = f"Invalid licenseref: {final_token!r}"
|
|
raise InvalidLicenseExpression(message)
|
|
normalized_tokens.append(license_refs[final_token] + suffix)
|
|
else:
|
|
if final_token not in LICENSES:
|
|
message = f"Unknown license: {final_token!r}"
|
|
raise InvalidLicenseExpression(message)
|
|
normalized_tokens.append(LICENSES[final_token]["id"] + suffix)
|
|
|
|
normalized_expression = " ".join(normalized_tokens)
|
|
|
|
return cast(
|
|
NormalizedLicenseExpression,
|
|
normalized_expression.replace("( ", "(").replace(" )", ")"),
|
|
)
|