nab-python 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nab_python/__init__.py +1 -0
- nab_python/_build/__init__.py +1 -0
- nab_python/_build/env.py +364 -0
- nab_python/_build/errors.py +17 -0
- nab_python/_build/runner.py +254 -0
- nab_python/_lockfile/__init__.py +1 -0
- nab_python/_lockfile/builder.py +339 -0
- nab_python/_lockfile/disjointness.py +207 -0
- nab_python/_lockfile/pylock.py +323 -0
- nab_python/_lockfile/requirements.py +121 -0
- nab_python/_packaging_provider.py +98 -0
- nab_python/_provider/__init__.py +1 -0
- nab_python/_provider/build_remote.py +95 -0
- nab_python/_provider/extras.py +231 -0
- nab_python/_provider/listing.py +442 -0
- nab_python/_provider/lookahead.py +156 -0
- nab_python/_provider/metadata_resolver.py +450 -0
- nab_python/_provider/priority.py +174 -0
- nab_python/_provider/sources.py +215 -0
- nab_python/_testing/__init__.py +1 -0
- nab_python/_testing/coordinator_fake.py +240 -0
- nab_python/_vcs_admission.py +209 -0
- nab_python/_vendor/__init__.py +6 -0
- nab_python/_vendor/packaging/LICENSE +3 -0
- nab_python/_vendor/packaging/LICENSE.APACHE +177 -0
- nab_python/_vendor/packaging/LICENSE.BSD +23 -0
- nab_python/_vendor/packaging/PROVENANCE.md +73 -0
- nab_python/_vendor/packaging/__init__.py +15 -0
- nab_python/_vendor/packaging/_elffile.py +108 -0
- nab_python/_vendor/packaging/_manylinux.py +265 -0
- nab_python/_vendor/packaging/_musllinux.py +88 -0
- nab_python/_vendor/packaging/_parser.py +394 -0
- nab_python/_vendor/packaging/_structures.py +33 -0
- nab_python/_vendor/packaging/_tokenizer.py +196 -0
- nab_python/_vendor/packaging/dependency_groups.py +302 -0
- nab_python/_vendor/packaging/direct_url.py +325 -0
- nab_python/_vendor/packaging/errors.py +94 -0
- nab_python/_vendor/packaging/licenses/__init__.py +186 -0
- nab_python/_vendor/packaging/licenses/_spdx.py +799 -0
- nab_python/_vendor/packaging/markers.py +506 -0
- nab_python/_vendor/packaging/metadata.py +964 -0
- nab_python/_vendor/packaging/py.typed +0 -0
- nab_python/_vendor/packaging/pylock.py +910 -0
- nab_python/_vendor/packaging/ranges.py +1803 -0
- nab_python/_vendor/packaging/requirements.py +132 -0
- nab_python/_vendor/packaging/specifiers.py +1141 -0
- nab_python/_vendor/packaging/tags.py +929 -0
- nab_python/_vendor/packaging/utils.py +296 -0
- nab_python/_vendor/packaging/version.py +1230 -0
- nab_python/build_backend.py +184 -0
- nab_python/config.py +805 -0
- nab_python/download.py +170 -0
- nab_python/fetch.py +827 -0
- nab_python/lockfile.py +238 -0
- nab_python/metadata.py +145 -0
- nab_python/provider.py +1235 -0
- nab_python/py.typed +0 -0
- nab_python/requirements_file.py +180 -0
- nab_python/resolve.py +497 -0
- nab_python/universal/__init__.py +1 -0
- nab_python/universal/matrix.py +235 -0
- nab_python/universal/provider.py +214 -0
- nab_python/universal/reresolve.py +310 -0
- nab_python/universal/resolve.py +508 -0
- nab_python/universal/validate.py +439 -0
- nab_python/universal/wheel_selection.py +327 -0
- nab_python/workspace.py +214 -0
- nab_python-0.0.1.dist-info/METADATA +49 -0
- nab_python-0.0.1.dist-info/RECORD +71 -0
- nab_python-0.0.1.dist-info/WHEEL +4 -0
- nab_python-0.0.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
4
|
+
import dataclasses
|
|
5
|
+
import sys
|
|
6
|
+
import typing
|
|
7
|
+
|
|
8
|
+
__all__ = ["ExceptionGroup"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def __dir__() -> list[str]:
|
|
12
|
+
return __all__
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
if sys.version_info >= (3, 11): # pragma: no cover
|
|
16
|
+
from builtins import ExceptionGroup
|
|
17
|
+
else: # pragma: no cover
|
|
18
|
+
|
|
19
|
+
class ExceptionGroup(Exception):
|
|
20
|
+
"""A minimal implementation of :external:exc:`ExceptionGroup` from Python 3.11.
|
|
21
|
+
|
|
22
|
+
If :external:exc:`ExceptionGroup` is already defined by Python itself,
|
|
23
|
+
that version is used instead.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
message: str
|
|
27
|
+
exceptions: list[Exception]
|
|
28
|
+
|
|
29
|
+
def __init__(self, message: str, exceptions: list[Exception]) -> None:
|
|
30
|
+
self.message = message
|
|
31
|
+
self.exceptions = exceptions
|
|
32
|
+
|
|
33
|
+
def __repr__(self) -> str:
|
|
34
|
+
return f"{self.__class__.__name__}({self.message!r}, {self.exceptions!r})"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclasses.dataclass
|
|
38
|
+
class _ErrorCollector:
|
|
39
|
+
"""
|
|
40
|
+
Collect errors into ExceptionGroups.
|
|
41
|
+
|
|
42
|
+
Used like this:
|
|
43
|
+
|
|
44
|
+
collector = _ErrorCollector()
|
|
45
|
+
# Add a single exception
|
|
46
|
+
collector.error(ValueError("one"))
|
|
47
|
+
|
|
48
|
+
# Supports nesting, including combining ExceptionGroups
|
|
49
|
+
with collector.collect():
|
|
50
|
+
raise ValueError("two")
|
|
51
|
+
collector.finalize("Found some errors")
|
|
52
|
+
|
|
53
|
+
Since making a collector and then calling finalize later is a common pattern,
|
|
54
|
+
a convenience method ``on_exit`` is provided.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
errors: list[Exception] = dataclasses.field(default_factory=list, init=False)
|
|
58
|
+
|
|
59
|
+
def finalize(self, msg: str) -> None:
|
|
60
|
+
"""Raise a group exception if there are any errors."""
|
|
61
|
+
if self.errors:
|
|
62
|
+
raise ExceptionGroup(msg, self.errors)
|
|
63
|
+
|
|
64
|
+
@contextlib.contextmanager
|
|
65
|
+
def on_exit(self, msg: str) -> typing.Generator[_ErrorCollector, None, None]:
|
|
66
|
+
"""
|
|
67
|
+
Calls finalize if no uncollected errors were present.
|
|
68
|
+
|
|
69
|
+
Uncollected errors are raised normally.
|
|
70
|
+
"""
|
|
71
|
+
yield self
|
|
72
|
+
self.finalize(msg)
|
|
73
|
+
|
|
74
|
+
@contextlib.contextmanager
|
|
75
|
+
def collect(self, *err_cls: type[Exception]) -> typing.Generator[None, None, None]:
|
|
76
|
+
"""
|
|
77
|
+
Context manager to collect errors into the error list.
|
|
78
|
+
|
|
79
|
+
Must be inside loops, as only one error can be collected at a time.
|
|
80
|
+
"""
|
|
81
|
+
error_classes = err_cls or (Exception,)
|
|
82
|
+
try:
|
|
83
|
+
yield
|
|
84
|
+
except ExceptionGroup as error:
|
|
85
|
+
self.errors.extend(error.exceptions)
|
|
86
|
+
except error_classes as error:
|
|
87
|
+
self.errors.append(error)
|
|
88
|
+
|
|
89
|
+
def error(
|
|
90
|
+
self,
|
|
91
|
+
error: Exception,
|
|
92
|
+
) -> None:
|
|
93
|
+
"""Add an error to the list."""
|
|
94
|
+
self.errors.append(error)
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#######################################################################################
|
|
2
|
+
#
|
|
3
|
+
# Adapted from:
|
|
4
|
+
# https://github.com/pypa/hatch/blob/5352e44/backend/src/hatchling/licenses/parse.py
|
|
5
|
+
#
|
|
6
|
+
# MIT License
|
|
7
|
+
#
|
|
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 this
|
|
11
|
+
# software and associated documentation files (the "Software"), to deal in the Software
|
|
12
|
+
# without restriction, including without limitation the rights to use, copy, modify,
|
|
13
|
+
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
|
14
|
+
# permit persons to whom the Software is furnished to do so, subject to the following
|
|
15
|
+
# conditions:
|
|
16
|
+
#
|
|
17
|
+
# The above copyright notice and this permission notice shall be included in all copies
|
|
18
|
+
# 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 A
|
|
22
|
+
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
23
|
+
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
24
|
+
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
25
|
+
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
26
|
+
#
|
|
27
|
+
#
|
|
28
|
+
# With additional allowance of arbitrary `LicenseRef-` identifiers, not just
|
|
29
|
+
# `LicenseRef-Public-Domain` and `LicenseRef-Proprietary`.
|
|
30
|
+
#
|
|
31
|
+
#######################################################################################
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import re
|
|
35
|
+
from typing import NewType, cast
|
|
36
|
+
|
|
37
|
+
from ._spdx import EXCEPTIONS, LICENSES
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"InvalidLicenseExpression",
|
|
41
|
+
"NormalizedLicenseExpression",
|
|
42
|
+
"canonicalize_license_expression",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Simple __dir__ implementation since there are no public submodules
|
|
47
|
+
def __dir__() -> list[str]:
|
|
48
|
+
return __all__
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
license_ref_allowed = re.compile("^[A-Za-z0-9.-]*$")
|
|
52
|
+
|
|
53
|
+
NormalizedLicenseExpression = NewType("NormalizedLicenseExpression", str)
|
|
54
|
+
"""
|
|
55
|
+
A :class:`typing.NewType` of :class:`str`, representing a normalized
|
|
56
|
+
License-Expression.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class InvalidLicenseExpression(ValueError):
|
|
61
|
+
"""Raised when a license-expression string is invalid
|
|
62
|
+
|
|
63
|
+
>>> from packaging.licenses import canonicalize_license_expression
|
|
64
|
+
>>> canonicalize_license_expression("invalid")
|
|
65
|
+
Traceback (most recent call last):
|
|
66
|
+
...
|
|
67
|
+
packaging.licenses.InvalidLicenseExpression: Invalid license expression: 'invalid'
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def canonicalize_license_expression(
|
|
72
|
+
raw_license_expression: str,
|
|
73
|
+
) -> NormalizedLicenseExpression:
|
|
74
|
+
"""
|
|
75
|
+
This function takes a valid License-Expression, and returns the normalized
|
|
76
|
+
form of it.
|
|
77
|
+
|
|
78
|
+
The return type is typed as :class:`NormalizedLicenseExpression`. This
|
|
79
|
+
allows type checkers to help require that a string has passed through this
|
|
80
|
+
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 an
|
|
84
|
+
invalid/unknown license identifier or invalid syntax.
|
|
85
|
+
|
|
86
|
+
.. doctest::
|
|
87
|
+
|
|
88
|
+
>>> from packaging.licenses import canonicalize_license_expression
|
|
89
|
+
>>> 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 on
|
|
107
|
+
# 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/exceptions
|
|
117
|
+
# 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 an
|
|
123
|
+
# expression that Python can parse. Everything that is not involved with the
|
|
124
|
+
# grammar itself is replaced with the placeholder `False` and the resultant
|
|
125
|
+
# 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_tokens
|
|
135
|
+
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 None
|
|
148
|
+
|
|
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
|
+
continue
|
|
155
|
+
|
|
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 = token
|
|
168
|
+
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
|
+
)
|