Publish GraphShieldMistral interactive explorer (part 4)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/_musllinux.py +85 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/_parser.py +393 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/_structures.py +33 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/_tokenizer.py +193 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/dependency_groups.py +302 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/direct_url.py +325 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/errors.py +94 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/licenses/__init__.py +186 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/licenses/_spdx.py +799 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/markers.py +492 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/metadata.py +964 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/py.typed +0 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/pylock.py +905 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/requirements.py +129 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/specifiers.py +1943 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/tags.py +932 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/utils.py +296 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/packaging/version.py +1231 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pkg_resources/LICENSE +17 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pkg_resources/__init__.py +0 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/LICENSE +21 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/__init__.py +917 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/__main__.py +66 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/_xdg.py +171 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/android.py +300 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/api.py +463 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/macos.py +223 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/py.typed +0 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/unix.py +321 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/version.py +24 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/windows.py +395 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/LICENSE +25 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/__init__.py +82 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/__main__.py +17 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/console.py +70 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/filter.py +70 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/filters/__init__.py +942 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/formatter.py +129 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/formatters/__init__.py +157 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/formatters/_mapping.py +23 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/lexer.py +965 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/lexers/__init__.py +362 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/lexers/_mapping.py +603 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/lexers/python.py +1204 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/modeline.py +43 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/plugin.py +74 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/regexopt.py +102 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/scanner.py +104 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/sphinxext.py +247 -0
- .venv/lib/python3.14/site-packages/pip/_vendor/pygments/style.py +203 -0
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/_musllinux.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""PEP 656 support.
|
| 2 |
+
|
| 3 |
+
This module implements logic to detect if the currently running Python is
|
| 4 |
+
linked against musl, and what musl version is used.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from __future__ import annotations
|
| 8 |
+
|
| 9 |
+
import functools
|
| 10 |
+
import re
|
| 11 |
+
import subprocess
|
| 12 |
+
import sys
|
| 13 |
+
from typing import Iterator, NamedTuple, Sequence
|
| 14 |
+
|
| 15 |
+
from ._elffile import ELFFile
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class _MuslVersion(NamedTuple):
|
| 19 |
+
major: int
|
| 20 |
+
minor: int
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def _parse_musl_version(output: str) -> _MuslVersion | None:
|
| 24 |
+
lines = [n for n in (n.strip() for n in output.splitlines()) if n]
|
| 25 |
+
if len(lines) < 2 or lines[0][:4] != "musl":
|
| 26 |
+
return None
|
| 27 |
+
m = re.match(r"Version (\d+)\.(\d+)", lines[1])
|
| 28 |
+
if not m:
|
| 29 |
+
return None
|
| 30 |
+
return _MuslVersion(major=int(m.group(1)), minor=int(m.group(2)))
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
@functools.lru_cache
|
| 34 |
+
def _get_musl_version(executable: str) -> _MuslVersion | None:
|
| 35 |
+
"""Detect currently-running musl runtime version.
|
| 36 |
+
|
| 37 |
+
This is done by checking the specified executable's dynamic linking
|
| 38 |
+
information, and invoking the loader to parse its output for a version
|
| 39 |
+
string. If the loader is musl, the output would be something like::
|
| 40 |
+
|
| 41 |
+
musl libc (x86_64)
|
| 42 |
+
Version 1.2.2
|
| 43 |
+
Dynamic Program Loader
|
| 44 |
+
"""
|
| 45 |
+
try:
|
| 46 |
+
with open(executable, "rb") as f:
|
| 47 |
+
ld = ELFFile(f).interpreter
|
| 48 |
+
except (OSError, TypeError, ValueError):
|
| 49 |
+
return None
|
| 50 |
+
if ld is None or "musl" not in ld:
|
| 51 |
+
return None
|
| 52 |
+
proc = subprocess.run([ld], check=False, stderr=subprocess.PIPE, text=True)
|
| 53 |
+
return _parse_musl_version(proc.stderr)
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def platform_tags(archs: Sequence[str]) -> Iterator[str]:
|
| 57 |
+
"""Generate musllinux tags compatible to the current platform.
|
| 58 |
+
|
| 59 |
+
:param archs: Sequence of compatible architectures.
|
| 60 |
+
The first one shall be the closest to the actual architecture and be the part of
|
| 61 |
+
platform tag after the ``linux_`` prefix, e.g. ``x86_64``.
|
| 62 |
+
The ``linux_`` prefix is assumed as a prerequisite for the current platform to
|
| 63 |
+
be musllinux-compatible.
|
| 64 |
+
|
| 65 |
+
:returns: An iterator of compatible musllinux tags.
|
| 66 |
+
"""
|
| 67 |
+
sys_musl = _get_musl_version(sys.executable)
|
| 68 |
+
if sys_musl is None: # Python not dynamically linked against musl.
|
| 69 |
+
return
|
| 70 |
+
for arch in archs:
|
| 71 |
+
for minor in range(sys_musl.minor, -1, -1):
|
| 72 |
+
yield f"musllinux_{sys_musl.major}_{minor}_{arch}"
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
if __name__ == "__main__": # pragma: no cover
|
| 76 |
+
import sysconfig
|
| 77 |
+
|
| 78 |
+
plat = sysconfig.get_platform()
|
| 79 |
+
assert plat.startswith("linux-"), "not linux"
|
| 80 |
+
|
| 81 |
+
print("plat:", plat)
|
| 82 |
+
print("musl:", _get_musl_version(sys.executable))
|
| 83 |
+
print("tags:", end=" ")
|
| 84 |
+
for t in platform_tags(re.sub(r"[.-]", "_", plat.split("-", 1)[-1])):
|
| 85 |
+
print(t, end="\n ")
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/_parser.py
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Handwritten parser of dependency specifiers.
|
| 2 |
+
|
| 3 |
+
The docstring for each __parse_* function contains EBNF-inspired grammar representing
|
| 4 |
+
the implementation.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from __future__ import annotations
|
| 8 |
+
|
| 9 |
+
import ast
|
| 10 |
+
from typing import List, Literal, NamedTuple, Sequence, Tuple, Union
|
| 11 |
+
|
| 12 |
+
from ._tokenizer import DEFAULT_RULES, Tokenizer
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class Node:
|
| 16 |
+
__slots__ = ("value",)
|
| 17 |
+
|
| 18 |
+
def __init__(self, value: str) -> None:
|
| 19 |
+
self.value = value
|
| 20 |
+
|
| 21 |
+
def __str__(self) -> str:
|
| 22 |
+
return self.value
|
| 23 |
+
|
| 24 |
+
def __repr__(self) -> str:
|
| 25 |
+
return f"<{self.__class__.__name__}({self.value!r})>"
|
| 26 |
+
|
| 27 |
+
def serialize(self) -> str:
|
| 28 |
+
raise NotImplementedError
|
| 29 |
+
|
| 30 |
+
def __getstate__(self) -> str:
|
| 31 |
+
# Return just the value string for compactness and stability.
|
| 32 |
+
return self.value
|
| 33 |
+
|
| 34 |
+
def _restore_value(self, value: object) -> None:
|
| 35 |
+
if not isinstance(value, str):
|
| 36 |
+
raise TypeError(
|
| 37 |
+
f"Cannot restore {self.__class__.__name__} value from {value!r}"
|
| 38 |
+
)
|
| 39 |
+
self.value = value
|
| 40 |
+
|
| 41 |
+
def __setstate__(self, state: object) -> None:
|
| 42 |
+
if isinstance(state, str):
|
| 43 |
+
# New format (26.2+): just the value string.
|
| 44 |
+
self._restore_value(state)
|
| 45 |
+
return
|
| 46 |
+
if isinstance(state, tuple) and len(state) == 2:
|
| 47 |
+
# Old format (packaging <= 26.0, __slots__): (None, {slot: value}).
|
| 48 |
+
_, slot_dict = state
|
| 49 |
+
if isinstance(slot_dict, dict) and "value" in slot_dict:
|
| 50 |
+
self._restore_value(slot_dict["value"])
|
| 51 |
+
return
|
| 52 |
+
if isinstance(state, dict) and "value" in state:
|
| 53 |
+
# Old format (packaging <= 25.0, no __slots__): plain __dict__.
|
| 54 |
+
self._restore_value(state["value"])
|
| 55 |
+
return
|
| 56 |
+
raise TypeError(f"Cannot restore {self.__class__.__name__} from {state!r}")
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
class Variable(Node):
|
| 60 |
+
__slots__ = ()
|
| 61 |
+
|
| 62 |
+
def serialize(self) -> str:
|
| 63 |
+
return str(self)
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
class Value(Node):
|
| 67 |
+
__slots__ = ()
|
| 68 |
+
|
| 69 |
+
def serialize(self) -> str:
|
| 70 |
+
return f'"{self}"'
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
class Op(Node):
|
| 74 |
+
__slots__ = ()
|
| 75 |
+
|
| 76 |
+
def serialize(self) -> str:
|
| 77 |
+
return str(self)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
MarkerLogical = Literal["and", "or"]
|
| 81 |
+
MarkerVar = Union[Variable, Value]
|
| 82 |
+
MarkerItem = Tuple[MarkerVar, Op, MarkerVar]
|
| 83 |
+
MarkerAtom = Union[MarkerItem, Sequence["MarkerAtom"]]
|
| 84 |
+
MarkerList = List[Union["MarkerList", MarkerAtom, MarkerLogical]]
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class ParsedRequirement(NamedTuple):
|
| 88 |
+
name: str
|
| 89 |
+
url: str
|
| 90 |
+
extras: list[str]
|
| 91 |
+
specifier: str
|
| 92 |
+
marker: MarkerList | None
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
# --------------------------------------------------------------------------------------
|
| 96 |
+
# Recursive descent parser for dependency specifier
|
| 97 |
+
# --------------------------------------------------------------------------------------
|
| 98 |
+
def parse_requirement(source: str) -> ParsedRequirement:
|
| 99 |
+
return _parse_requirement(Tokenizer(source, rules=DEFAULT_RULES))
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def _parse_requirement(tokenizer: Tokenizer) -> ParsedRequirement:
|
| 103 |
+
"""
|
| 104 |
+
requirement = WS? IDENTIFIER WS? extras WS? requirement_details
|
| 105 |
+
"""
|
| 106 |
+
tokenizer.consume("WS")
|
| 107 |
+
|
| 108 |
+
name_token = tokenizer.expect(
|
| 109 |
+
"IDENTIFIER", expected="package name at the start of dependency specifier"
|
| 110 |
+
)
|
| 111 |
+
name = name_token.text
|
| 112 |
+
tokenizer.consume("WS")
|
| 113 |
+
|
| 114 |
+
extras = _parse_extras(tokenizer)
|
| 115 |
+
tokenizer.consume("WS")
|
| 116 |
+
|
| 117 |
+
url, specifier, marker = _parse_requirement_details(tokenizer)
|
| 118 |
+
tokenizer.expect("END", expected="end of dependency specifier")
|
| 119 |
+
|
| 120 |
+
return ParsedRequirement(name, url, extras, specifier, marker)
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def _parse_requirement_details(
|
| 124 |
+
tokenizer: Tokenizer,
|
| 125 |
+
) -> tuple[str, str, MarkerList | None]:
|
| 126 |
+
"""
|
| 127 |
+
requirement_details = AT URL (WS requirement_marker?)?
|
| 128 |
+
| specifier WS? (requirement_marker)?
|
| 129 |
+
"""
|
| 130 |
+
|
| 131 |
+
specifier = ""
|
| 132 |
+
url = ""
|
| 133 |
+
marker = None
|
| 134 |
+
|
| 135 |
+
if tokenizer.check("AT"):
|
| 136 |
+
tokenizer.read()
|
| 137 |
+
tokenizer.consume("WS")
|
| 138 |
+
|
| 139 |
+
url_start = tokenizer.position
|
| 140 |
+
url = tokenizer.expect("URL", expected="URL after @").text
|
| 141 |
+
if tokenizer.check("END", peek=True):
|
| 142 |
+
return (url, specifier, marker)
|
| 143 |
+
|
| 144 |
+
tokenizer.expect("WS", expected="whitespace after URL")
|
| 145 |
+
|
| 146 |
+
# The input might end after whitespace.
|
| 147 |
+
if tokenizer.check("END", peek=True):
|
| 148 |
+
return (url, specifier, marker)
|
| 149 |
+
|
| 150 |
+
marker = _parse_requirement_marker(
|
| 151 |
+
tokenizer,
|
| 152 |
+
span_start=url_start,
|
| 153 |
+
expected="semicolon (after URL and whitespace)",
|
| 154 |
+
)
|
| 155 |
+
else:
|
| 156 |
+
specifier_start = tokenizer.position
|
| 157 |
+
specifier = _parse_specifier(tokenizer)
|
| 158 |
+
tokenizer.consume("WS")
|
| 159 |
+
|
| 160 |
+
if tokenizer.check("END", peek=True):
|
| 161 |
+
return (url, specifier, marker)
|
| 162 |
+
|
| 163 |
+
marker = _parse_requirement_marker(
|
| 164 |
+
tokenizer,
|
| 165 |
+
span_start=specifier_start,
|
| 166 |
+
expected=(
|
| 167 |
+
"comma (within version specifier), semicolon (after version specifier)"
|
| 168 |
+
if specifier
|
| 169 |
+
else "semicolon (after name with no version specifier)"
|
| 170 |
+
),
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
return (url, specifier, marker)
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def _parse_requirement_marker(
|
| 177 |
+
tokenizer: Tokenizer, *, span_start: int, expected: str
|
| 178 |
+
) -> MarkerList:
|
| 179 |
+
"""
|
| 180 |
+
requirement_marker = SEMICOLON marker WS?
|
| 181 |
+
"""
|
| 182 |
+
|
| 183 |
+
if not tokenizer.check("SEMICOLON"):
|
| 184 |
+
tokenizer.raise_syntax_error(
|
| 185 |
+
f"Expected {expected} or end",
|
| 186 |
+
span_start=span_start,
|
| 187 |
+
span_end=None,
|
| 188 |
+
)
|
| 189 |
+
tokenizer.read()
|
| 190 |
+
|
| 191 |
+
marker = _parse_marker(tokenizer)
|
| 192 |
+
tokenizer.consume("WS")
|
| 193 |
+
|
| 194 |
+
return marker
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
def _parse_extras(tokenizer: Tokenizer) -> list[str]:
|
| 198 |
+
"""
|
| 199 |
+
extras = (LEFT_BRACKET wsp* extras_list? wsp* RIGHT_BRACKET)?
|
| 200 |
+
"""
|
| 201 |
+
if not tokenizer.check("LEFT_BRACKET", peek=True):
|
| 202 |
+
return []
|
| 203 |
+
|
| 204 |
+
with tokenizer.enclosing_tokens(
|
| 205 |
+
"LEFT_BRACKET",
|
| 206 |
+
"RIGHT_BRACKET",
|
| 207 |
+
around="extras",
|
| 208 |
+
):
|
| 209 |
+
tokenizer.consume("WS")
|
| 210 |
+
extras = _parse_extras_list(tokenizer)
|
| 211 |
+
tokenizer.consume("WS")
|
| 212 |
+
|
| 213 |
+
return extras
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
def _parse_extras_list(tokenizer: Tokenizer) -> list[str]:
|
| 217 |
+
"""
|
| 218 |
+
extras_list = identifier (wsp* ',' wsp* identifier)*
|
| 219 |
+
"""
|
| 220 |
+
extras: list[str] = []
|
| 221 |
+
|
| 222 |
+
if not tokenizer.check("IDENTIFIER"):
|
| 223 |
+
return extras
|
| 224 |
+
|
| 225 |
+
extras.append(tokenizer.read().text)
|
| 226 |
+
|
| 227 |
+
while True:
|
| 228 |
+
tokenizer.consume("WS")
|
| 229 |
+
if tokenizer.check("IDENTIFIER", peek=True):
|
| 230 |
+
tokenizer.raise_syntax_error("Expected comma between extra names")
|
| 231 |
+
elif not tokenizer.check("COMMA"):
|
| 232 |
+
break
|
| 233 |
+
|
| 234 |
+
tokenizer.read()
|
| 235 |
+
tokenizer.consume("WS")
|
| 236 |
+
|
| 237 |
+
extra_token = tokenizer.expect("IDENTIFIER", expected="extra name after comma")
|
| 238 |
+
extras.append(extra_token.text)
|
| 239 |
+
|
| 240 |
+
return extras
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
def _parse_specifier(tokenizer: Tokenizer) -> str:
|
| 244 |
+
"""
|
| 245 |
+
specifier = LEFT_PARENTHESIS WS? version_many WS? RIGHT_PARENTHESIS
|
| 246 |
+
| WS? version_many WS?
|
| 247 |
+
"""
|
| 248 |
+
with tokenizer.enclosing_tokens(
|
| 249 |
+
"LEFT_PARENTHESIS",
|
| 250 |
+
"RIGHT_PARENTHESIS",
|
| 251 |
+
around="version specifier",
|
| 252 |
+
):
|
| 253 |
+
tokenizer.consume("WS")
|
| 254 |
+
parsed_specifiers = _parse_version_many(tokenizer)
|
| 255 |
+
tokenizer.consume("WS")
|
| 256 |
+
|
| 257 |
+
return parsed_specifiers
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
def _parse_version_many(tokenizer: Tokenizer) -> str:
|
| 261 |
+
"""
|
| 262 |
+
version_many = (SPECIFIER (WS? COMMA WS? SPECIFIER)*)?
|
| 263 |
+
"""
|
| 264 |
+
parsed_specifiers = ""
|
| 265 |
+
while tokenizer.check("SPECIFIER"):
|
| 266 |
+
span_start = tokenizer.position
|
| 267 |
+
parsed_specifiers += tokenizer.read().text
|
| 268 |
+
if tokenizer.check("VERSION_PREFIX_TRAIL", peek=True):
|
| 269 |
+
tokenizer.raise_syntax_error(
|
| 270 |
+
".* suffix can only be used with `==` or `!=` operators",
|
| 271 |
+
span_start=span_start,
|
| 272 |
+
span_end=tokenizer.position + 1,
|
| 273 |
+
)
|
| 274 |
+
if tokenizer.check("VERSION_LOCAL_LABEL_TRAIL", peek=True):
|
| 275 |
+
tokenizer.raise_syntax_error(
|
| 276 |
+
"Local version label can only be used with `==` or `!=` operators",
|
| 277 |
+
span_start=span_start,
|
| 278 |
+
span_end=tokenizer.position,
|
| 279 |
+
)
|
| 280 |
+
tokenizer.consume("WS")
|
| 281 |
+
if not tokenizer.check("COMMA"):
|
| 282 |
+
break
|
| 283 |
+
parsed_specifiers += tokenizer.read().text
|
| 284 |
+
tokenizer.consume("WS")
|
| 285 |
+
|
| 286 |
+
return parsed_specifiers
|
| 287 |
+
|
| 288 |
+
|
| 289 |
+
# --------------------------------------------------------------------------------------
|
| 290 |
+
# Recursive descent parser for marker expression
|
| 291 |
+
# --------------------------------------------------------------------------------------
|
| 292 |
+
def parse_marker(source: str) -> MarkerList:
|
| 293 |
+
return _parse_full_marker(Tokenizer(source, rules=DEFAULT_RULES))
|
| 294 |
+
|
| 295 |
+
|
| 296 |
+
def _parse_full_marker(tokenizer: Tokenizer) -> MarkerList:
|
| 297 |
+
retval = _parse_marker(tokenizer)
|
| 298 |
+
tokenizer.expect("END", expected="end of marker expression")
|
| 299 |
+
return retval
|
| 300 |
+
|
| 301 |
+
|
| 302 |
+
def _parse_marker(tokenizer: Tokenizer) -> MarkerList:
|
| 303 |
+
"""
|
| 304 |
+
marker = marker_atom (BOOLOP marker_atom)+
|
| 305 |
+
"""
|
| 306 |
+
expression = [_parse_marker_atom(tokenizer)]
|
| 307 |
+
while tokenizer.check("BOOLOP"):
|
| 308 |
+
token = tokenizer.read()
|
| 309 |
+
expr_right = _parse_marker_atom(tokenizer)
|
| 310 |
+
expression.extend((token.text, expr_right))
|
| 311 |
+
return expression
|
| 312 |
+
|
| 313 |
+
|
| 314 |
+
def _parse_marker_atom(tokenizer: Tokenizer) -> MarkerAtom:
|
| 315 |
+
"""
|
| 316 |
+
marker_atom = WS? LEFT_PARENTHESIS WS? marker WS? RIGHT_PARENTHESIS WS?
|
| 317 |
+
| WS? marker_item WS?
|
| 318 |
+
"""
|
| 319 |
+
|
| 320 |
+
tokenizer.consume("WS")
|
| 321 |
+
if tokenizer.check("LEFT_PARENTHESIS", peek=True):
|
| 322 |
+
with tokenizer.enclosing_tokens(
|
| 323 |
+
"LEFT_PARENTHESIS",
|
| 324 |
+
"RIGHT_PARENTHESIS",
|
| 325 |
+
around="marker expression",
|
| 326 |
+
):
|
| 327 |
+
tokenizer.consume("WS")
|
| 328 |
+
marker: MarkerAtom = _parse_marker(tokenizer)
|
| 329 |
+
tokenizer.consume("WS")
|
| 330 |
+
else:
|
| 331 |
+
marker = _parse_marker_item(tokenizer)
|
| 332 |
+
tokenizer.consume("WS")
|
| 333 |
+
return marker
|
| 334 |
+
|
| 335 |
+
|
| 336 |
+
def _parse_marker_item(tokenizer: Tokenizer) -> MarkerItem:
|
| 337 |
+
"""
|
| 338 |
+
marker_item = WS? marker_var WS? marker_op WS? marker_var WS?
|
| 339 |
+
"""
|
| 340 |
+
tokenizer.consume("WS")
|
| 341 |
+
marker_var_left = _parse_marker_var(tokenizer)
|
| 342 |
+
tokenizer.consume("WS")
|
| 343 |
+
marker_op = _parse_marker_op(tokenizer)
|
| 344 |
+
tokenizer.consume("WS")
|
| 345 |
+
marker_var_right = _parse_marker_var(tokenizer)
|
| 346 |
+
tokenizer.consume("WS")
|
| 347 |
+
return (marker_var_left, marker_op, marker_var_right)
|
| 348 |
+
|
| 349 |
+
|
| 350 |
+
def _parse_marker_var(tokenizer: Tokenizer) -> MarkerVar: # noqa: RET503
|
| 351 |
+
"""
|
| 352 |
+
marker_var = VARIABLE | QUOTED_STRING
|
| 353 |
+
"""
|
| 354 |
+
if tokenizer.check("VARIABLE"):
|
| 355 |
+
return process_env_var(tokenizer.read().text.replace(".", "_"))
|
| 356 |
+
elif tokenizer.check("QUOTED_STRING"):
|
| 357 |
+
return process_python_str(tokenizer.read().text)
|
| 358 |
+
else:
|
| 359 |
+
tokenizer.raise_syntax_error(
|
| 360 |
+
message="Expected a marker variable or quoted string"
|
| 361 |
+
)
|
| 362 |
+
|
| 363 |
+
|
| 364 |
+
def process_env_var(env_var: str) -> Variable:
|
| 365 |
+
if env_var in ("platform_python_implementation", "python_implementation"):
|
| 366 |
+
return Variable("platform_python_implementation")
|
| 367 |
+
else:
|
| 368 |
+
return Variable(env_var)
|
| 369 |
+
|
| 370 |
+
|
| 371 |
+
def process_python_str(python_str: str) -> Value:
|
| 372 |
+
value = ast.literal_eval(python_str)
|
| 373 |
+
return Value(str(value))
|
| 374 |
+
|
| 375 |
+
|
| 376 |
+
def _parse_marker_op(tokenizer: Tokenizer) -> Op:
|
| 377 |
+
"""
|
| 378 |
+
marker_op = IN | NOT IN | OP
|
| 379 |
+
"""
|
| 380 |
+
if tokenizer.check("IN"):
|
| 381 |
+
tokenizer.read()
|
| 382 |
+
return Op("in")
|
| 383 |
+
elif tokenizer.check("NOT"):
|
| 384 |
+
tokenizer.read()
|
| 385 |
+
tokenizer.expect("WS", expected="whitespace after 'not'")
|
| 386 |
+
tokenizer.expect("IN", expected="'in' after 'not'")
|
| 387 |
+
return Op("not in")
|
| 388 |
+
elif tokenizer.check("OP"):
|
| 389 |
+
return Op(tokenizer.read().text)
|
| 390 |
+
else:
|
| 391 |
+
return tokenizer.raise_syntax_error(
|
| 392 |
+
"Expected marker operator, one of <=, <, !=, ==, >=, >, ~=, ===, in, not in"
|
| 393 |
+
)
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/_structures.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
|
| 5 |
+
"""Backward-compatibility shim for unpickling Version objects serialized before
|
| 6 |
+
packaging 26.1.
|
| 7 |
+
|
| 8 |
+
Old pickles reference ``packaging._structures.InfinityType`` and
|
| 9 |
+
``packaging._structures.NegativeInfinityType``. This module provides minimal
|
| 10 |
+
stand-in classes so that ``pickle.loads()`` can resolve those references.
|
| 11 |
+
The deserialized objects are not used for comparisons — ``Version.__setstate__``
|
| 12 |
+
discards the stale ``_key`` cache and recomputes it from the core version fields.
|
| 13 |
+
"""
|
| 14 |
+
|
| 15 |
+
from __future__ import annotations
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class InfinityType:
|
| 19 |
+
"""Stand-in for the removed ``InfinityType`` used in old comparison keys."""
|
| 20 |
+
|
| 21 |
+
def __repr__(self) -> str:
|
| 22 |
+
return "Infinity"
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class NegativeInfinityType:
|
| 26 |
+
"""Stand-in for the removed ``NegativeInfinityType`` used in old comparison keys."""
|
| 27 |
+
|
| 28 |
+
def __repr__(self) -> str:
|
| 29 |
+
return "-Infinity"
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
Infinity = InfinityType()
|
| 33 |
+
NegativeInfinity = NegativeInfinityType()
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/_tokenizer.py
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import contextlib
|
| 4 |
+
import re
|
| 5 |
+
from dataclasses import dataclass
|
| 6 |
+
from typing import Generator, Mapping, NoReturn
|
| 7 |
+
|
| 8 |
+
from .specifiers import Specifier
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@dataclass
|
| 12 |
+
class Token:
|
| 13 |
+
name: str
|
| 14 |
+
text: str
|
| 15 |
+
position: int
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class ParserSyntaxError(Exception):
|
| 19 |
+
"""The provided source text could not be parsed correctly."""
|
| 20 |
+
|
| 21 |
+
def __init__(
|
| 22 |
+
self,
|
| 23 |
+
message: str,
|
| 24 |
+
*,
|
| 25 |
+
source: str,
|
| 26 |
+
span: tuple[int, int],
|
| 27 |
+
) -> None:
|
| 28 |
+
self.span = span
|
| 29 |
+
self.message = message
|
| 30 |
+
self.source = source
|
| 31 |
+
|
| 32 |
+
super().__init__()
|
| 33 |
+
|
| 34 |
+
def __str__(self) -> str:
|
| 35 |
+
marker = " " * self.span[0] + "~" * (self.span[1] - self.span[0]) + "^"
|
| 36 |
+
return f"{self.message}\n {self.source}\n {marker}"
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
DEFAULT_RULES: dict[str, re.Pattern[str]] = {
|
| 40 |
+
"LEFT_PARENTHESIS": re.compile(r"\("),
|
| 41 |
+
"RIGHT_PARENTHESIS": re.compile(r"\)"),
|
| 42 |
+
"LEFT_BRACKET": re.compile(r"\["),
|
| 43 |
+
"RIGHT_BRACKET": re.compile(r"\]"),
|
| 44 |
+
"SEMICOLON": re.compile(r";"),
|
| 45 |
+
"COMMA": re.compile(r","),
|
| 46 |
+
"QUOTED_STRING": re.compile(
|
| 47 |
+
r"""
|
| 48 |
+
(
|
| 49 |
+
('[^']*')
|
| 50 |
+
|
|
| 51 |
+
("[^"]*")
|
| 52 |
+
)
|
| 53 |
+
""",
|
| 54 |
+
re.VERBOSE,
|
| 55 |
+
),
|
| 56 |
+
"OP": re.compile(r"(===|==|~=|!=|<=|>=|<|>)"),
|
| 57 |
+
"BOOLOP": re.compile(r"\b(or|and)\b"),
|
| 58 |
+
"IN": re.compile(r"\bin\b"),
|
| 59 |
+
"NOT": re.compile(r"\bnot\b"),
|
| 60 |
+
"VARIABLE": re.compile(
|
| 61 |
+
r"""
|
| 62 |
+
\b(
|
| 63 |
+
python_version
|
| 64 |
+
|python_full_version
|
| 65 |
+
|os[._]name
|
| 66 |
+
|sys[._]platform
|
| 67 |
+
|platform_(release|system)
|
| 68 |
+
|platform[._](version|machine|python_implementation)
|
| 69 |
+
|python_implementation
|
| 70 |
+
|implementation_(name|version)
|
| 71 |
+
|extras?
|
| 72 |
+
|dependency_groups
|
| 73 |
+
)\b
|
| 74 |
+
""",
|
| 75 |
+
re.VERBOSE,
|
| 76 |
+
),
|
| 77 |
+
"SPECIFIER": re.compile(
|
| 78 |
+
Specifier._specifier_regex_str,
|
| 79 |
+
re.VERBOSE | re.IGNORECASE,
|
| 80 |
+
),
|
| 81 |
+
"AT": re.compile(r"\@"),
|
| 82 |
+
"URL": re.compile(r"[^ \t]+"),
|
| 83 |
+
"IDENTIFIER": re.compile(r"\b[a-zA-Z0-9][a-zA-Z0-9._-]*\b"),
|
| 84 |
+
"VERSION_PREFIX_TRAIL": re.compile(r"\.\*"),
|
| 85 |
+
"VERSION_LOCAL_LABEL_TRAIL": re.compile(r"\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*"),
|
| 86 |
+
"WS": re.compile(r"[ \t]+"),
|
| 87 |
+
"END": re.compile(r"$"),
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
class Tokenizer:
|
| 92 |
+
"""Context-sensitive token parsing.
|
| 93 |
+
|
| 94 |
+
Provides methods to examine the input stream to check whether the next token
|
| 95 |
+
matches.
|
| 96 |
+
"""
|
| 97 |
+
|
| 98 |
+
def __init__(
|
| 99 |
+
self,
|
| 100 |
+
source: str,
|
| 101 |
+
*,
|
| 102 |
+
rules: Mapping[str, re.Pattern[str]],
|
| 103 |
+
) -> None:
|
| 104 |
+
self.source = source
|
| 105 |
+
self.rules = rules
|
| 106 |
+
self.next_token: Token | None = None
|
| 107 |
+
self.position = 0
|
| 108 |
+
|
| 109 |
+
def consume(self, name: str) -> None:
|
| 110 |
+
"""Move beyond provided token name, if at current position."""
|
| 111 |
+
if self.check(name):
|
| 112 |
+
self.read()
|
| 113 |
+
|
| 114 |
+
def check(self, name: str, *, peek: bool = False) -> bool:
|
| 115 |
+
"""Check whether the next token has the provided name.
|
| 116 |
+
|
| 117 |
+
By default, if the check succeeds, the token *must* be read before
|
| 118 |
+
another check. If `peek` is set to `True`, the token is not loaded and
|
| 119 |
+
would need to be checked again.
|
| 120 |
+
"""
|
| 121 |
+
assert self.next_token is None, (
|
| 122 |
+
f"Cannot check for {name!r}, already have {self.next_token!r}"
|
| 123 |
+
)
|
| 124 |
+
assert name in self.rules, f"Unknown token name: {name!r}"
|
| 125 |
+
|
| 126 |
+
expression = self.rules[name]
|
| 127 |
+
|
| 128 |
+
match = expression.match(self.source, self.position)
|
| 129 |
+
if match is None:
|
| 130 |
+
return False
|
| 131 |
+
if not peek:
|
| 132 |
+
self.next_token = Token(name, match[0], self.position)
|
| 133 |
+
return True
|
| 134 |
+
|
| 135 |
+
def expect(self, name: str, *, expected: str) -> Token:
|
| 136 |
+
"""Expect a certain token name next, failing with a syntax error otherwise.
|
| 137 |
+
|
| 138 |
+
The token is *not* read.
|
| 139 |
+
"""
|
| 140 |
+
if not self.check(name):
|
| 141 |
+
raise self.raise_syntax_error(f"Expected {expected}")
|
| 142 |
+
return self.read()
|
| 143 |
+
|
| 144 |
+
def read(self) -> Token:
|
| 145 |
+
"""Consume the next token and return it."""
|
| 146 |
+
token = self.next_token
|
| 147 |
+
assert token is not None
|
| 148 |
+
|
| 149 |
+
self.position += len(token.text)
|
| 150 |
+
self.next_token = None
|
| 151 |
+
|
| 152 |
+
return token
|
| 153 |
+
|
| 154 |
+
def raise_syntax_error(
|
| 155 |
+
self,
|
| 156 |
+
message: str,
|
| 157 |
+
*,
|
| 158 |
+
span_start: int | None = None,
|
| 159 |
+
span_end: int | None = None,
|
| 160 |
+
) -> NoReturn:
|
| 161 |
+
"""Raise ParserSyntaxError at the given position."""
|
| 162 |
+
span = (
|
| 163 |
+
self.position if span_start is None else span_start,
|
| 164 |
+
self.position if span_end is None else span_end,
|
| 165 |
+
)
|
| 166 |
+
raise ParserSyntaxError(
|
| 167 |
+
message,
|
| 168 |
+
source=self.source,
|
| 169 |
+
span=span,
|
| 170 |
+
)
|
| 171 |
+
|
| 172 |
+
@contextlib.contextmanager
|
| 173 |
+
def enclosing_tokens(
|
| 174 |
+
self, open_token: str, close_token: str, *, around: str
|
| 175 |
+
) -> Generator[None, None, None]:
|
| 176 |
+
if self.check(open_token):
|
| 177 |
+
open_position = self.position
|
| 178 |
+
self.read()
|
| 179 |
+
else:
|
| 180 |
+
open_position = None
|
| 181 |
+
|
| 182 |
+
yield
|
| 183 |
+
|
| 184 |
+
if open_position is None:
|
| 185 |
+
return
|
| 186 |
+
|
| 187 |
+
if not self.check(close_token):
|
| 188 |
+
self.raise_syntax_error(
|
| 189 |
+
f"Expected matching {close_token} for {open_token}, after {around}",
|
| 190 |
+
span_start=open_position,
|
| 191 |
+
)
|
| 192 |
+
|
| 193 |
+
self.read()
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/dependency_groups.py
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import re
|
| 4 |
+
from collections.abc import Mapping, Sequence
|
| 5 |
+
|
| 6 |
+
from .errors import _ErrorCollector
|
| 7 |
+
from .requirements import Requirement
|
| 8 |
+
|
| 9 |
+
__all__ = [
|
| 10 |
+
"CyclicDependencyGroup",
|
| 11 |
+
"DependencyGroupInclude",
|
| 12 |
+
"DependencyGroupResolver",
|
| 13 |
+
"DuplicateGroupNames",
|
| 14 |
+
"InvalidDependencyGroupObject",
|
| 15 |
+
"resolve_dependency_groups",
|
| 16 |
+
]
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def __dir__() -> list[str]:
|
| 20 |
+
return __all__
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
# -----------
|
| 24 |
+
# Error Types
|
| 25 |
+
# -----------
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class DuplicateGroupNames(ValueError):
|
| 29 |
+
"""
|
| 30 |
+
The same dependency groups were defined twice, with different non-normalized names.
|
| 31 |
+
"""
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class CyclicDependencyGroup(ValueError):
|
| 35 |
+
"""
|
| 36 |
+
The dependency group includes form a cycle.
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
def __init__(self, requested_group: str, group: str, include_group: str) -> None:
|
| 40 |
+
self.requested_group = requested_group
|
| 41 |
+
self.group = group
|
| 42 |
+
self.include_group = include_group
|
| 43 |
+
|
| 44 |
+
if include_group == group:
|
| 45 |
+
reason = f"{group} includes itself"
|
| 46 |
+
else:
|
| 47 |
+
reason = f"{include_group} -> {group}, {group} -> {include_group}"
|
| 48 |
+
super().__init__(
|
| 49 |
+
"Cyclic dependency group include while resolving "
|
| 50 |
+
f"{requested_group}: {reason}"
|
| 51 |
+
)
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
# in the PEP 735 spec, the tables in dependency group lists were described as
|
| 55 |
+
# "Dependency Object Specifiers", but the only defined type of object was a
|
| 56 |
+
# "Dependency Group Include" -- hence the naming of this error as "Object"
|
| 57 |
+
class InvalidDependencyGroupObject(ValueError):
|
| 58 |
+
"""
|
| 59 |
+
A member of a dependency group was identified as a dict, but was not in a valid
|
| 60 |
+
format.
|
| 61 |
+
"""
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
# ------------------------
|
| 65 |
+
# Object Model & Interface
|
| 66 |
+
# ------------------------
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
class DependencyGroupInclude:
|
| 70 |
+
__slots__ = ("include_group",)
|
| 71 |
+
|
| 72 |
+
def __init__(self, include_group: str) -> None:
|
| 73 |
+
"""
|
| 74 |
+
Initialize a DependencyGroupInclude.
|
| 75 |
+
|
| 76 |
+
:param include_group: The name of the group referred to by this include.
|
| 77 |
+
"""
|
| 78 |
+
self.include_group = include_group
|
| 79 |
+
|
| 80 |
+
def __repr__(self) -> str:
|
| 81 |
+
return f"{self.__class__.__name__}({self.include_group!r})"
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
class DependencyGroupResolver:
|
| 85 |
+
"""
|
| 86 |
+
A resolver for Dependency Group data.
|
| 87 |
+
|
| 88 |
+
This class handles caching, name normalization, cycle detection, and other
|
| 89 |
+
parsing requirements. There are only two public methods for exploring the data:
|
| 90 |
+
``lookup()`` and ``resolve()``.
|
| 91 |
+
|
| 92 |
+
:param dependency_groups: A mapping, as provided via pyproject
|
| 93 |
+
``[dependency-groups]``.
|
| 94 |
+
"""
|
| 95 |
+
|
| 96 |
+
def __init__(
|
| 97 |
+
self,
|
| 98 |
+
dependency_groups: Mapping[str, Sequence[str | Mapping[str, str]]],
|
| 99 |
+
) -> None:
|
| 100 |
+
errors = _ErrorCollector()
|
| 101 |
+
|
| 102 |
+
self.dependency_groups = _normalize_group_names(dependency_groups, errors)
|
| 103 |
+
|
| 104 |
+
# a map of group names to parsed data
|
| 105 |
+
self._parsed_groups: dict[
|
| 106 |
+
str, tuple[Requirement | DependencyGroupInclude, ...]
|
| 107 |
+
] = {}
|
| 108 |
+
# a map of group names to their ancestors, used for cycle detection
|
| 109 |
+
self._include_graph_ancestors: dict[str, tuple[str, ...]] = {}
|
| 110 |
+
# a cache of completed resolutions to Requirement lists
|
| 111 |
+
self._resolve_cache: dict[str, tuple[Requirement, ...]] = {}
|
| 112 |
+
|
| 113 |
+
errors.finalize("[dependency-groups] data was invalid")
|
| 114 |
+
|
| 115 |
+
def lookup(self, group: str) -> tuple[Requirement | DependencyGroupInclude, ...]:
|
| 116 |
+
"""
|
| 117 |
+
Lookup a group name, returning the parsed dependency data for that group.
|
| 118 |
+
This will not resolve includes.
|
| 119 |
+
|
| 120 |
+
:param group: the name of the group to lookup
|
| 121 |
+
"""
|
| 122 |
+
group = _normalize_name(group)
|
| 123 |
+
|
| 124 |
+
with _ErrorCollector().on_exit(
|
| 125 |
+
f"[dependency-groups] data for {group!r} was malformed"
|
| 126 |
+
) as errors:
|
| 127 |
+
return self._parse_group(group, errors)
|
| 128 |
+
|
| 129 |
+
def resolve(self, group: str) -> tuple[Requirement, ...]:
|
| 130 |
+
"""
|
| 131 |
+
Resolve a dependency group to a list of requirements.
|
| 132 |
+
|
| 133 |
+
:param group: the name of the group to resolve
|
| 134 |
+
"""
|
| 135 |
+
group = _normalize_name(group)
|
| 136 |
+
|
| 137 |
+
with _ErrorCollector().on_exit(
|
| 138 |
+
f"[dependency-groups] data for {group!r} was malformed"
|
| 139 |
+
) as errors:
|
| 140 |
+
return self._resolve(group, group, errors)
|
| 141 |
+
|
| 142 |
+
def _resolve(
|
| 143 |
+
self, group: str, requested_group: str, errors: _ErrorCollector
|
| 144 |
+
) -> tuple[Requirement, ...]:
|
| 145 |
+
"""
|
| 146 |
+
This is a helper for cached resolution to strings. It preserves the name of the
|
| 147 |
+
group which the user initially requested in order to present a clearer error in
|
| 148 |
+
the event that a cycle is detected.
|
| 149 |
+
|
| 150 |
+
:param group: The normalized name of the group to resolve.
|
| 151 |
+
:param requested_group: The group which was used in the original, user-facing
|
| 152 |
+
request.
|
| 153 |
+
"""
|
| 154 |
+
if group in self._resolve_cache:
|
| 155 |
+
return self._resolve_cache[group]
|
| 156 |
+
|
| 157 |
+
parsed = self._parse_group(group, errors)
|
| 158 |
+
|
| 159 |
+
resolved_group = []
|
| 160 |
+
|
| 161 |
+
for item in parsed:
|
| 162 |
+
if isinstance(item, Requirement):
|
| 163 |
+
resolved_group.append(item)
|
| 164 |
+
elif isinstance(item, DependencyGroupInclude):
|
| 165 |
+
include_group = _normalize_name(item.include_group)
|
| 166 |
+
|
| 167 |
+
# if a group is cyclic, record the error
|
| 168 |
+
# otherwise, follow the include_group reference
|
| 169 |
+
#
|
| 170 |
+
# this allows us to examine all includes in a group, even in the
|
| 171 |
+
# presence of errors
|
| 172 |
+
if include_group in self._include_graph_ancestors.get(group, ()):
|
| 173 |
+
errors.error(
|
| 174 |
+
CyclicDependencyGroup(
|
| 175 |
+
requested_group, group, item.include_group
|
| 176 |
+
)
|
| 177 |
+
)
|
| 178 |
+
else:
|
| 179 |
+
self._include_graph_ancestors[include_group] = (
|
| 180 |
+
*self._include_graph_ancestors.get(group, ()),
|
| 181 |
+
group,
|
| 182 |
+
)
|
| 183 |
+
resolved_group.extend(
|
| 184 |
+
self._resolve(include_group, requested_group, errors)
|
| 185 |
+
)
|
| 186 |
+
else: # pragma: no cover
|
| 187 |
+
raise NotImplementedError(
|
| 188 |
+
f"Invalid dependency group item after parse: {item}"
|
| 189 |
+
)
|
| 190 |
+
|
| 191 |
+
# in the event that errors were detected, present the group as empty and do not
|
| 192 |
+
# cache the result
|
| 193 |
+
# this ensures that repeated access to a cyclic group will raise multiple errors
|
| 194 |
+
if errors.errors:
|
| 195 |
+
return ()
|
| 196 |
+
|
| 197 |
+
self._resolve_cache[group] = tuple(resolved_group)
|
| 198 |
+
return self._resolve_cache[group]
|
| 199 |
+
|
| 200 |
+
def _parse_group(
|
| 201 |
+
self, group: str, errors: _ErrorCollector
|
| 202 |
+
) -> tuple[Requirement | DependencyGroupInclude, ...]:
|
| 203 |
+
# short circuit -- never do the work twice
|
| 204 |
+
if group in self._parsed_groups:
|
| 205 |
+
return self._parsed_groups[group]
|
| 206 |
+
|
| 207 |
+
if group not in self.dependency_groups:
|
| 208 |
+
errors.error(LookupError(f"Dependency group '{group}' not found"))
|
| 209 |
+
return ()
|
| 210 |
+
|
| 211 |
+
raw_group = self.dependency_groups[group]
|
| 212 |
+
if isinstance(raw_group, str):
|
| 213 |
+
errors.error(
|
| 214 |
+
TypeError(
|
| 215 |
+
f"Dependency group {group!r} contained a string rather than a list."
|
| 216 |
+
)
|
| 217 |
+
)
|
| 218 |
+
return ()
|
| 219 |
+
|
| 220 |
+
if not isinstance(raw_group, Sequence):
|
| 221 |
+
errors.error(
|
| 222 |
+
TypeError(f"Dependency group {group!r} is not a sequence type.")
|
| 223 |
+
)
|
| 224 |
+
return ()
|
| 225 |
+
|
| 226 |
+
elements: list[Requirement | DependencyGroupInclude] = []
|
| 227 |
+
for item in raw_group:
|
| 228 |
+
if isinstance(item, str):
|
| 229 |
+
# packaging.requirements.Requirement parsing ensures that this is a
|
| 230 |
+
# valid PEP 508 Dependency Specifier
|
| 231 |
+
# raises InvalidRequirement on failure
|
| 232 |
+
elements.append(Requirement(item))
|
| 233 |
+
elif isinstance(item, Mapping):
|
| 234 |
+
if tuple(item.keys()) != ("include-group",):
|
| 235 |
+
errors.error(
|
| 236 |
+
InvalidDependencyGroupObject(
|
| 237 |
+
f"Invalid dependency group item: {item!r}"
|
| 238 |
+
)
|
| 239 |
+
)
|
| 240 |
+
else:
|
| 241 |
+
include_group = item["include-group"]
|
| 242 |
+
elements.append(DependencyGroupInclude(include_group=include_group))
|
| 243 |
+
else:
|
| 244 |
+
errors.error(TypeError(f"Invalid dependency group item: {item!r}"))
|
| 245 |
+
|
| 246 |
+
self._parsed_groups[group] = tuple(elements)
|
| 247 |
+
return self._parsed_groups[group]
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
# --------------------
|
| 251 |
+
# Functional Interface
|
| 252 |
+
# --------------------
|
| 253 |
+
|
| 254 |
+
|
| 255 |
+
def resolve_dependency_groups(
|
| 256 |
+
dependency_groups: Mapping[str, Sequence[str | Mapping[str, str]]], /, *groups: str
|
| 257 |
+
) -> tuple[str, ...]:
|
| 258 |
+
"""
|
| 259 |
+
Resolve a dependency group to a tuple of requirements, as strings.
|
| 260 |
+
|
| 261 |
+
:param dependency_groups: the parsed contents of the ``[dependency-groups]`` table
|
| 262 |
+
from ``pyproject.toml``
|
| 263 |
+
:param groups: the name of the group(s) to resolve
|
| 264 |
+
"""
|
| 265 |
+
resolver = DependencyGroupResolver(dependency_groups)
|
| 266 |
+
return tuple(str(r) for group in groups for r in resolver.resolve(group))
|
| 267 |
+
|
| 268 |
+
|
| 269 |
+
# ----------------
|
| 270 |
+
# internal helpers
|
| 271 |
+
# ----------------
|
| 272 |
+
|
| 273 |
+
|
| 274 |
+
_NORMALIZE_PATTERN = re.compile(r"[-_.]+")
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
def _normalize_name(name: str) -> str:
|
| 278 |
+
return _NORMALIZE_PATTERN.sub("-", name).lower()
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
def _normalize_group_names(
|
| 282 |
+
dependency_groups: Mapping[str, Sequence[str | Mapping[str, str]]],
|
| 283 |
+
errors: _ErrorCollector,
|
| 284 |
+
) -> dict[str, Sequence[str | Mapping[str, str]]]:
|
| 285 |
+
original_names: dict[str, list[str]] = {}
|
| 286 |
+
normalized_groups: dict[str, Sequence[str | Mapping[str, str]]] = {}
|
| 287 |
+
|
| 288 |
+
for group_name, value in dependency_groups.items():
|
| 289 |
+
normed_group_name = _normalize_name(group_name)
|
| 290 |
+
original_names.setdefault(normed_group_name, []).append(group_name)
|
| 291 |
+
normalized_groups[normed_group_name] = value
|
| 292 |
+
|
| 293 |
+
for normed_name, names in original_names.items():
|
| 294 |
+
if len(names) > 1:
|
| 295 |
+
errors.error(
|
| 296 |
+
DuplicateGroupNames(
|
| 297 |
+
"Duplicate dependency group names: "
|
| 298 |
+
f"{normed_name} ({', '.join(names)})"
|
| 299 |
+
)
|
| 300 |
+
)
|
| 301 |
+
|
| 302 |
+
return normalized_groups
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/direct_url.py
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import dataclasses
|
| 4 |
+
import re
|
| 5 |
+
import urllib.parse
|
| 6 |
+
from collections.abc import Mapping
|
| 7 |
+
from typing import TYPE_CHECKING, Any, Protocol, TypeVar
|
| 8 |
+
|
| 9 |
+
if TYPE_CHECKING: # pragma: no cover
|
| 10 |
+
import sys
|
| 11 |
+
from collections.abc import Collection
|
| 12 |
+
|
| 13 |
+
if sys.version_info >= (3, 11):
|
| 14 |
+
from typing import Self
|
| 15 |
+
else:
|
| 16 |
+
from typing_extensions import Self
|
| 17 |
+
|
| 18 |
+
__all__ = [
|
| 19 |
+
"ArchiveInfo",
|
| 20 |
+
"DirInfo",
|
| 21 |
+
"DirectUrl",
|
| 22 |
+
"DirectUrlValidationError",
|
| 23 |
+
"VcsInfo",
|
| 24 |
+
]
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def __dir__() -> list[str]:
|
| 28 |
+
return __all__
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
_T = TypeVar("_T")
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class _FromMappingProtocol(Protocol): # pragma: no cover
|
| 35 |
+
@classmethod
|
| 36 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self: ...
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
_FromMappingProtocolT = TypeVar("_FromMappingProtocolT", bound=_FromMappingProtocol)
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def _json_dict_factory(data: list[tuple[str, Any]]) -> dict[str, Any]:
|
| 43 |
+
return {key: value for key, value in data if value is not None}
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def _get(d: Mapping[str, Any], expected_type: type[_T], key: str) -> _T | None:
|
| 47 |
+
"""Get a value from the dictionary and verify it's the expected type."""
|
| 48 |
+
if (value := d.get(key)) is None:
|
| 49 |
+
return None
|
| 50 |
+
if not isinstance(value, expected_type):
|
| 51 |
+
raise DirectUrlValidationError(
|
| 52 |
+
f"Unexpected type {type(value).__name__} "
|
| 53 |
+
f"(expected {expected_type.__name__})",
|
| 54 |
+
context=key,
|
| 55 |
+
)
|
| 56 |
+
return value
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def _get_required(d: Mapping[str, Any], expected_type: type[_T], key: str) -> _T:
|
| 60 |
+
"""Get a required value from the dictionary and verify it's the expected type."""
|
| 61 |
+
if (value := _get(d, expected_type, key)) is None:
|
| 62 |
+
raise _DirectUrlRequiredKeyError(key)
|
| 63 |
+
return value
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def _get_object(
|
| 67 |
+
d: Mapping[str, Any], target_type: type[_FromMappingProtocolT], key: str
|
| 68 |
+
) -> _FromMappingProtocolT | None:
|
| 69 |
+
"""Get a dictionary value from the dictionary and convert it to a dataclass."""
|
| 70 |
+
if (value := _get(d, Mapping, key)) is None: # type: ignore[type-abstract]
|
| 71 |
+
return None
|
| 72 |
+
try:
|
| 73 |
+
return target_type._from_dict(value)
|
| 74 |
+
except Exception as e:
|
| 75 |
+
raise DirectUrlValidationError(e, context=key) from e
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
_PEP610_USER_PASS_ENV_VARS_REGEX = re.compile(
|
| 79 |
+
r"^\$\{[A-Za-z0-9-_]+\}(:\$\{[A-Za-z0-9-_]+\})?$"
|
| 80 |
+
)
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def _strip_auth_from_netloc(netloc: str, safe_user_passwords: Collection[str]) -> str:
|
| 84 |
+
if "@" not in netloc:
|
| 85 |
+
return netloc
|
| 86 |
+
user_pass, netloc_no_user_pass = netloc.split("@", 1)
|
| 87 |
+
if user_pass in safe_user_passwords:
|
| 88 |
+
return netloc
|
| 89 |
+
if _PEP610_USER_PASS_ENV_VARS_REGEX.match(user_pass):
|
| 90 |
+
return netloc
|
| 91 |
+
return netloc_no_user_pass
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def _strip_url(url: str, safe_user_passwords: Collection[str]) -> str:
|
| 95 |
+
"""url with user:password part removed unless it is formed with
|
| 96 |
+
environment variables as specified in PEP 610, or it is a safe user:password
|
| 97 |
+
such as `git`.
|
| 98 |
+
"""
|
| 99 |
+
parsed_url = urllib.parse.urlsplit(url)
|
| 100 |
+
netloc = _strip_auth_from_netloc(parsed_url.netloc, safe_user_passwords)
|
| 101 |
+
return urllib.parse.urlunsplit(
|
| 102 |
+
(
|
| 103 |
+
parsed_url.scheme,
|
| 104 |
+
netloc,
|
| 105 |
+
parsed_url.path,
|
| 106 |
+
parsed_url.query,
|
| 107 |
+
parsed_url.fragment,
|
| 108 |
+
)
|
| 109 |
+
)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
class DirectUrlValidationError(Exception):
|
| 113 |
+
"""Raised when when input data is not spec-compliant."""
|
| 114 |
+
|
| 115 |
+
context: str | None = None
|
| 116 |
+
message: str
|
| 117 |
+
|
| 118 |
+
def __init__(
|
| 119 |
+
self,
|
| 120 |
+
cause: str | Exception,
|
| 121 |
+
*,
|
| 122 |
+
context: str | None = None,
|
| 123 |
+
) -> None:
|
| 124 |
+
if isinstance(cause, DirectUrlValidationError):
|
| 125 |
+
if cause.context:
|
| 126 |
+
self.context = (
|
| 127 |
+
f"{context}.{cause.context}" if context else cause.context
|
| 128 |
+
)
|
| 129 |
+
else:
|
| 130 |
+
self.context = context # pragma: no cover
|
| 131 |
+
self.message = cause.message
|
| 132 |
+
else:
|
| 133 |
+
self.context = context
|
| 134 |
+
self.message = str(cause)
|
| 135 |
+
|
| 136 |
+
def __str__(self) -> str:
|
| 137 |
+
if self.context:
|
| 138 |
+
return f"{self.message} in {self.context!r}"
|
| 139 |
+
return self.message
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
class _DirectUrlRequiredKeyError(DirectUrlValidationError):
|
| 143 |
+
def __init__(self, key: str) -> None:
|
| 144 |
+
super().__init__("Missing required value", context=key)
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
@dataclasses.dataclass(frozen=True, init=False)
|
| 148 |
+
class VcsInfo:
|
| 149 |
+
vcs: str
|
| 150 |
+
commit_id: str
|
| 151 |
+
requested_revision: str | None = None
|
| 152 |
+
|
| 153 |
+
def __init__(
|
| 154 |
+
self,
|
| 155 |
+
*,
|
| 156 |
+
vcs: str,
|
| 157 |
+
commit_id: str,
|
| 158 |
+
requested_revision: str | None = None,
|
| 159 |
+
) -> None:
|
| 160 |
+
object.__setattr__(self, "vcs", vcs)
|
| 161 |
+
object.__setattr__(self, "commit_id", commit_id)
|
| 162 |
+
object.__setattr__(self, "requested_revision", requested_revision)
|
| 163 |
+
|
| 164 |
+
@classmethod
|
| 165 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self:
|
| 166 |
+
# We can't validate vcs value because is not closed.
|
| 167 |
+
return cls(
|
| 168 |
+
vcs=_get_required(d, str, "vcs"),
|
| 169 |
+
requested_revision=_get(d, str, "requested_revision"),
|
| 170 |
+
commit_id=_get_required(d, str, "commit_id"),
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
@dataclasses.dataclass(frozen=True, init=False)
|
| 175 |
+
class ArchiveInfo:
|
| 176 |
+
hashes: Mapping[str, str] | None = None
|
| 177 |
+
|
| 178 |
+
def __init__(
|
| 179 |
+
self,
|
| 180 |
+
*,
|
| 181 |
+
hashes: Mapping[str, str] | None = None,
|
| 182 |
+
) -> None:
|
| 183 |
+
object.__setattr__(self, "hashes", hashes)
|
| 184 |
+
|
| 185 |
+
@classmethod
|
| 186 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self:
|
| 187 |
+
hashes = _get(d, Mapping, "hashes") # type: ignore[type-abstract]
|
| 188 |
+
if hashes is not None and not all(isinstance(h, str) for h in hashes.values()):
|
| 189 |
+
raise DirectUrlValidationError(
|
| 190 |
+
"Hash values must be strings", context="hashes"
|
| 191 |
+
)
|
| 192 |
+
legacy_hash = _get(d, str, "hash")
|
| 193 |
+
if legacy_hash is not None:
|
| 194 |
+
if "=" not in legacy_hash:
|
| 195 |
+
raise DirectUrlValidationError(
|
| 196 |
+
"Invalid hash format (expected '<algorithm>=<hash>')",
|
| 197 |
+
context="hash",
|
| 198 |
+
)
|
| 199 |
+
hash_algorithm, hash_value = legacy_hash.split("=", 1)
|
| 200 |
+
if hashes is None:
|
| 201 |
+
# if `hashes` are not present, we can derive it from the legacy `hash`
|
| 202 |
+
hashes = {hash_algorithm: hash_value}
|
| 203 |
+
else:
|
| 204 |
+
# if `hashes` are present, the legacy `hash` must match one of them
|
| 205 |
+
if hash_algorithm not in hashes:
|
| 206 |
+
raise DirectUrlValidationError(
|
| 207 |
+
f"Algorithm {hash_algorithm!r} used in hash field "
|
| 208 |
+
f"is not present in hashes field",
|
| 209 |
+
context="hashes",
|
| 210 |
+
)
|
| 211 |
+
if hashes[hash_algorithm] != hash_value:
|
| 212 |
+
raise DirectUrlValidationError(
|
| 213 |
+
f"Algorithm {hash_algorithm!r} used in hash field "
|
| 214 |
+
f"has different value in hashes field",
|
| 215 |
+
context="hash",
|
| 216 |
+
)
|
| 217 |
+
return cls(hashes=hashes)
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
@dataclasses.dataclass(frozen=True, init=False)
|
| 221 |
+
class DirInfo:
|
| 222 |
+
editable: bool | None = None
|
| 223 |
+
|
| 224 |
+
def __init__(
|
| 225 |
+
self,
|
| 226 |
+
*,
|
| 227 |
+
editable: bool | None = None,
|
| 228 |
+
) -> None:
|
| 229 |
+
object.__setattr__(self, "editable", editable)
|
| 230 |
+
|
| 231 |
+
@classmethod
|
| 232 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self:
|
| 233 |
+
return cls(
|
| 234 |
+
editable=_get(d, bool, "editable"),
|
| 235 |
+
)
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
@dataclasses.dataclass(frozen=True, init=False)
|
| 239 |
+
class DirectUrl:
|
| 240 |
+
"""A class representing a direct URL."""
|
| 241 |
+
|
| 242 |
+
url: str
|
| 243 |
+
archive_info: ArchiveInfo | None = None
|
| 244 |
+
vcs_info: VcsInfo | None = None
|
| 245 |
+
dir_info: DirInfo | None = None
|
| 246 |
+
subdirectory: str | None = None # XXX Path or str?
|
| 247 |
+
|
| 248 |
+
def __init__(
|
| 249 |
+
self,
|
| 250 |
+
*,
|
| 251 |
+
url: str,
|
| 252 |
+
archive_info: ArchiveInfo | None = None,
|
| 253 |
+
vcs_info: VcsInfo | None = None,
|
| 254 |
+
dir_info: DirInfo | None = None,
|
| 255 |
+
subdirectory: str | None = None,
|
| 256 |
+
) -> None:
|
| 257 |
+
object.__setattr__(self, "url", url)
|
| 258 |
+
object.__setattr__(self, "archive_info", archive_info)
|
| 259 |
+
object.__setattr__(self, "vcs_info", vcs_info)
|
| 260 |
+
object.__setattr__(self, "dir_info", dir_info)
|
| 261 |
+
object.__setattr__(self, "subdirectory", subdirectory)
|
| 262 |
+
|
| 263 |
+
@classmethod
|
| 264 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self:
|
| 265 |
+
direct_url = cls(
|
| 266 |
+
url=_get_required(d, str, "url"),
|
| 267 |
+
archive_info=_get_object(d, ArchiveInfo, "archive_info"),
|
| 268 |
+
vcs_info=_get_object(d, VcsInfo, "vcs_info"),
|
| 269 |
+
dir_info=_get_object(d, DirInfo, "dir_info"),
|
| 270 |
+
subdirectory=_get(d, str, "subdirectory"),
|
| 271 |
+
)
|
| 272 |
+
if (
|
| 273 |
+
bool(direct_url.vcs_info)
|
| 274 |
+
+ bool(direct_url.archive_info)
|
| 275 |
+
+ bool(direct_url.dir_info)
|
| 276 |
+
) != 1:
|
| 277 |
+
raise DirectUrlValidationError(
|
| 278 |
+
"Exactly one of vcs_info, archive_info, dir_info must be present"
|
| 279 |
+
)
|
| 280 |
+
if direct_url.dir_info is not None and not direct_url.url.startswith("file://"):
|
| 281 |
+
raise DirectUrlValidationError(
|
| 282 |
+
"URL scheme must be file:// when dir_info is present",
|
| 283 |
+
context="url",
|
| 284 |
+
)
|
| 285 |
+
# XXX subdirectory must be relative, can we, should we validate that here?
|
| 286 |
+
return direct_url
|
| 287 |
+
|
| 288 |
+
@classmethod
|
| 289 |
+
def from_dict(cls, d: Mapping[str, Any], /) -> Self:
|
| 290 |
+
"""Create and validate a DirectUrl instance from a JSON dictionary."""
|
| 291 |
+
return cls._from_dict(d)
|
| 292 |
+
|
| 293 |
+
def to_dict(
|
| 294 |
+
self,
|
| 295 |
+
*,
|
| 296 |
+
generate_legacy_hash: bool = False,
|
| 297 |
+
strip_user_password: bool = True,
|
| 298 |
+
safe_user_passwords: Collection[str] = ("git",),
|
| 299 |
+
) -> Mapping[str, Any]:
|
| 300 |
+
"""Convert the DirectUrl instance to a JSON dictionary.
|
| 301 |
+
|
| 302 |
+
:param generate_legacy_hash: If True, include a legacy `hash` field in
|
| 303 |
+
`archive_info` for backward compatibility with tools that don't
|
| 304 |
+
support the `hashes` field.
|
| 305 |
+
:param strip_user_password: If True, strip user:password from the URL
|
| 306 |
+
unless it is formed with environment variables as specified in PEP
|
| 307 |
+
610, or it is a safe user:password such as `git`.
|
| 308 |
+
:param safe_user_passwords: A collection of user:password strings that
|
| 309 |
+
should not be stripped from the URL even if `strip_user_password` is
|
| 310 |
+
True.
|
| 311 |
+
"""
|
| 312 |
+
res = dataclasses.asdict(self, dict_factory=_json_dict_factory)
|
| 313 |
+
if generate_legacy_hash and self.archive_info and self.archive_info.hashes:
|
| 314 |
+
hash_algorithm, hash_value = next(iter(self.archive_info.hashes.items()))
|
| 315 |
+
res["archive_info"]["hash"] = f"{hash_algorithm}={hash_value}"
|
| 316 |
+
if strip_user_password:
|
| 317 |
+
res["url"] = _strip_url(self.url, safe_user_passwords)
|
| 318 |
+
return res
|
| 319 |
+
|
| 320 |
+
def validate(self) -> None:
|
| 321 |
+
"""Validate the DirectUrl instance against the specification.
|
| 322 |
+
|
| 323 |
+
Raises :class:`DirectUrlValidationError` if invalid.
|
| 324 |
+
"""
|
| 325 |
+
self.from_dict(self.to_dict())
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/errors.py
ADDED
|
@@ -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)
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/licenses/__init__.py
ADDED
|
@@ -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 |
+
)
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/licenses/_spdx.py
ADDED
|
@@ -0,0 +1,799 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
from typing import TypedDict
|
| 5 |
+
|
| 6 |
+
class SPDXLicense(TypedDict):
|
| 7 |
+
id: str
|
| 8 |
+
deprecated: bool
|
| 9 |
+
|
| 10 |
+
class SPDXException(TypedDict):
|
| 11 |
+
id: str
|
| 12 |
+
deprecated: bool
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
VERSION = '3.27.0'
|
| 16 |
+
|
| 17 |
+
LICENSES: dict[str, SPDXLicense] = {
|
| 18 |
+
'0bsd': {'id': '0BSD', 'deprecated': False},
|
| 19 |
+
'3d-slicer-1.0': {'id': '3D-Slicer-1.0', 'deprecated': False},
|
| 20 |
+
'aal': {'id': 'AAL', 'deprecated': False},
|
| 21 |
+
'abstyles': {'id': 'Abstyles', 'deprecated': False},
|
| 22 |
+
'adacore-doc': {'id': 'AdaCore-doc', 'deprecated': False},
|
| 23 |
+
'adobe-2006': {'id': 'Adobe-2006', 'deprecated': False},
|
| 24 |
+
'adobe-display-postscript': {'id': 'Adobe-Display-PostScript', 'deprecated': False},
|
| 25 |
+
'adobe-glyph': {'id': 'Adobe-Glyph', 'deprecated': False},
|
| 26 |
+
'adobe-utopia': {'id': 'Adobe-Utopia', 'deprecated': False},
|
| 27 |
+
'adsl': {'id': 'ADSL', 'deprecated': False},
|
| 28 |
+
'afl-1.1': {'id': 'AFL-1.1', 'deprecated': False},
|
| 29 |
+
'afl-1.2': {'id': 'AFL-1.2', 'deprecated': False},
|
| 30 |
+
'afl-2.0': {'id': 'AFL-2.0', 'deprecated': False},
|
| 31 |
+
'afl-2.1': {'id': 'AFL-2.1', 'deprecated': False},
|
| 32 |
+
'afl-3.0': {'id': 'AFL-3.0', 'deprecated': False},
|
| 33 |
+
'afmparse': {'id': 'Afmparse', 'deprecated': False},
|
| 34 |
+
'agpl-1.0': {'id': 'AGPL-1.0', 'deprecated': True},
|
| 35 |
+
'agpl-1.0-only': {'id': 'AGPL-1.0-only', 'deprecated': False},
|
| 36 |
+
'agpl-1.0-or-later': {'id': 'AGPL-1.0-or-later', 'deprecated': False},
|
| 37 |
+
'agpl-3.0': {'id': 'AGPL-3.0', 'deprecated': True},
|
| 38 |
+
'agpl-3.0-only': {'id': 'AGPL-3.0-only', 'deprecated': False},
|
| 39 |
+
'agpl-3.0-or-later': {'id': 'AGPL-3.0-or-later', 'deprecated': False},
|
| 40 |
+
'aladdin': {'id': 'Aladdin', 'deprecated': False},
|
| 41 |
+
'amd-newlib': {'id': 'AMD-newlib', 'deprecated': False},
|
| 42 |
+
'amdplpa': {'id': 'AMDPLPA', 'deprecated': False},
|
| 43 |
+
'aml': {'id': 'AML', 'deprecated': False},
|
| 44 |
+
'aml-glslang': {'id': 'AML-glslang', 'deprecated': False},
|
| 45 |
+
'ampas': {'id': 'AMPAS', 'deprecated': False},
|
| 46 |
+
'antlr-pd': {'id': 'ANTLR-PD', 'deprecated': False},
|
| 47 |
+
'antlr-pd-fallback': {'id': 'ANTLR-PD-fallback', 'deprecated': False},
|
| 48 |
+
'any-osi': {'id': 'any-OSI', 'deprecated': False},
|
| 49 |
+
'any-osi-perl-modules': {'id': 'any-OSI-perl-modules', 'deprecated': False},
|
| 50 |
+
'apache-1.0': {'id': 'Apache-1.0', 'deprecated': False},
|
| 51 |
+
'apache-1.1': {'id': 'Apache-1.1', 'deprecated': False},
|
| 52 |
+
'apache-2.0': {'id': 'Apache-2.0', 'deprecated': False},
|
| 53 |
+
'apafml': {'id': 'APAFML', 'deprecated': False},
|
| 54 |
+
'apl-1.0': {'id': 'APL-1.0', 'deprecated': False},
|
| 55 |
+
'app-s2p': {'id': 'App-s2p', 'deprecated': False},
|
| 56 |
+
'apsl-1.0': {'id': 'APSL-1.0', 'deprecated': False},
|
| 57 |
+
'apsl-1.1': {'id': 'APSL-1.1', 'deprecated': False},
|
| 58 |
+
'apsl-1.2': {'id': 'APSL-1.2', 'deprecated': False},
|
| 59 |
+
'apsl-2.0': {'id': 'APSL-2.0', 'deprecated': False},
|
| 60 |
+
'arphic-1999': {'id': 'Arphic-1999', 'deprecated': False},
|
| 61 |
+
'artistic-1.0': {'id': 'Artistic-1.0', 'deprecated': False},
|
| 62 |
+
'artistic-1.0-cl8': {'id': 'Artistic-1.0-cl8', 'deprecated': False},
|
| 63 |
+
'artistic-1.0-perl': {'id': 'Artistic-1.0-Perl', 'deprecated': False},
|
| 64 |
+
'artistic-2.0': {'id': 'Artistic-2.0', 'deprecated': False},
|
| 65 |
+
'artistic-dist': {'id': 'Artistic-dist', 'deprecated': False},
|
| 66 |
+
'aspell-ru': {'id': 'Aspell-RU', 'deprecated': False},
|
| 67 |
+
'aswf-digital-assets-1.0': {'id': 'ASWF-Digital-Assets-1.0', 'deprecated': False},
|
| 68 |
+
'aswf-digital-assets-1.1': {'id': 'ASWF-Digital-Assets-1.1', 'deprecated': False},
|
| 69 |
+
'baekmuk': {'id': 'Baekmuk', 'deprecated': False},
|
| 70 |
+
'bahyph': {'id': 'Bahyph', 'deprecated': False},
|
| 71 |
+
'barr': {'id': 'Barr', 'deprecated': False},
|
| 72 |
+
'bcrypt-solar-designer': {'id': 'bcrypt-Solar-Designer', 'deprecated': False},
|
| 73 |
+
'beerware': {'id': 'Beerware', 'deprecated': False},
|
| 74 |
+
'bitstream-charter': {'id': 'Bitstream-Charter', 'deprecated': False},
|
| 75 |
+
'bitstream-vera': {'id': 'Bitstream-Vera', 'deprecated': False},
|
| 76 |
+
'bittorrent-1.0': {'id': 'BitTorrent-1.0', 'deprecated': False},
|
| 77 |
+
'bittorrent-1.1': {'id': 'BitTorrent-1.1', 'deprecated': False},
|
| 78 |
+
'blessing': {'id': 'blessing', 'deprecated': False},
|
| 79 |
+
'blueoak-1.0.0': {'id': 'BlueOak-1.0.0', 'deprecated': False},
|
| 80 |
+
'boehm-gc': {'id': 'Boehm-GC', 'deprecated': False},
|
| 81 |
+
'boehm-gc-without-fee': {'id': 'Boehm-GC-without-fee', 'deprecated': False},
|
| 82 |
+
'borceux': {'id': 'Borceux', 'deprecated': False},
|
| 83 |
+
'brian-gladman-2-clause': {'id': 'Brian-Gladman-2-Clause', 'deprecated': False},
|
| 84 |
+
'brian-gladman-3-clause': {'id': 'Brian-Gladman-3-Clause', 'deprecated': False},
|
| 85 |
+
'bsd-1-clause': {'id': 'BSD-1-Clause', 'deprecated': False},
|
| 86 |
+
'bsd-2-clause': {'id': 'BSD-2-Clause', 'deprecated': False},
|
| 87 |
+
'bsd-2-clause-darwin': {'id': 'BSD-2-Clause-Darwin', 'deprecated': False},
|
| 88 |
+
'bsd-2-clause-first-lines': {'id': 'BSD-2-Clause-first-lines', 'deprecated': False},
|
| 89 |
+
'bsd-2-clause-freebsd': {'id': 'BSD-2-Clause-FreeBSD', 'deprecated': True},
|
| 90 |
+
'bsd-2-clause-netbsd': {'id': 'BSD-2-Clause-NetBSD', 'deprecated': True},
|
| 91 |
+
'bsd-2-clause-patent': {'id': 'BSD-2-Clause-Patent', 'deprecated': False},
|
| 92 |
+
'bsd-2-clause-pkgconf-disclaimer': {'id': 'BSD-2-Clause-pkgconf-disclaimer', 'deprecated': False},
|
| 93 |
+
'bsd-2-clause-views': {'id': 'BSD-2-Clause-Views', 'deprecated': False},
|
| 94 |
+
'bsd-3-clause': {'id': 'BSD-3-Clause', 'deprecated': False},
|
| 95 |
+
'bsd-3-clause-acpica': {'id': 'BSD-3-Clause-acpica', 'deprecated': False},
|
| 96 |
+
'bsd-3-clause-attribution': {'id': 'BSD-3-Clause-Attribution', 'deprecated': False},
|
| 97 |
+
'bsd-3-clause-clear': {'id': 'BSD-3-Clause-Clear', 'deprecated': False},
|
| 98 |
+
'bsd-3-clause-flex': {'id': 'BSD-3-Clause-flex', 'deprecated': False},
|
| 99 |
+
'bsd-3-clause-hp': {'id': 'BSD-3-Clause-HP', 'deprecated': False},
|
| 100 |
+
'bsd-3-clause-lbnl': {'id': 'BSD-3-Clause-LBNL', 'deprecated': False},
|
| 101 |
+
'bsd-3-clause-modification': {'id': 'BSD-3-Clause-Modification', 'deprecated': False},
|
| 102 |
+
'bsd-3-clause-no-military-license': {'id': 'BSD-3-Clause-No-Military-License', 'deprecated': False},
|
| 103 |
+
'bsd-3-clause-no-nuclear-license': {'id': 'BSD-3-Clause-No-Nuclear-License', 'deprecated': False},
|
| 104 |
+
'bsd-3-clause-no-nuclear-license-2014': {'id': 'BSD-3-Clause-No-Nuclear-License-2014', 'deprecated': False},
|
| 105 |
+
'bsd-3-clause-no-nuclear-warranty': {'id': 'BSD-3-Clause-No-Nuclear-Warranty', 'deprecated': False},
|
| 106 |
+
'bsd-3-clause-open-mpi': {'id': 'BSD-3-Clause-Open-MPI', 'deprecated': False},
|
| 107 |
+
'bsd-3-clause-sun': {'id': 'BSD-3-Clause-Sun', 'deprecated': False},
|
| 108 |
+
'bsd-4-clause': {'id': 'BSD-4-Clause', 'deprecated': False},
|
| 109 |
+
'bsd-4-clause-shortened': {'id': 'BSD-4-Clause-Shortened', 'deprecated': False},
|
| 110 |
+
'bsd-4-clause-uc': {'id': 'BSD-4-Clause-UC', 'deprecated': False},
|
| 111 |
+
'bsd-4.3reno': {'id': 'BSD-4.3RENO', 'deprecated': False},
|
| 112 |
+
'bsd-4.3tahoe': {'id': 'BSD-4.3TAHOE', 'deprecated': False},
|
| 113 |
+
'bsd-advertising-acknowledgement': {'id': 'BSD-Advertising-Acknowledgement', 'deprecated': False},
|
| 114 |
+
'bsd-attribution-hpnd-disclaimer': {'id': 'BSD-Attribution-HPND-disclaimer', 'deprecated': False},
|
| 115 |
+
'bsd-inferno-nettverk': {'id': 'BSD-Inferno-Nettverk', 'deprecated': False},
|
| 116 |
+
'bsd-protection': {'id': 'BSD-Protection', 'deprecated': False},
|
| 117 |
+
'bsd-source-beginning-file': {'id': 'BSD-Source-beginning-file', 'deprecated': False},
|
| 118 |
+
'bsd-source-code': {'id': 'BSD-Source-Code', 'deprecated': False},
|
| 119 |
+
'bsd-systemics': {'id': 'BSD-Systemics', 'deprecated': False},
|
| 120 |
+
'bsd-systemics-w3works': {'id': 'BSD-Systemics-W3Works', 'deprecated': False},
|
| 121 |
+
'bsl-1.0': {'id': 'BSL-1.0', 'deprecated': False},
|
| 122 |
+
'busl-1.1': {'id': 'BUSL-1.1', 'deprecated': False},
|
| 123 |
+
'bzip2-1.0.5': {'id': 'bzip2-1.0.5', 'deprecated': True},
|
| 124 |
+
'bzip2-1.0.6': {'id': 'bzip2-1.0.6', 'deprecated': False},
|
| 125 |
+
'c-uda-1.0': {'id': 'C-UDA-1.0', 'deprecated': False},
|
| 126 |
+
'cal-1.0': {'id': 'CAL-1.0', 'deprecated': False},
|
| 127 |
+
'cal-1.0-combined-work-exception': {'id': 'CAL-1.0-Combined-Work-Exception', 'deprecated': False},
|
| 128 |
+
'caldera': {'id': 'Caldera', 'deprecated': False},
|
| 129 |
+
'caldera-no-preamble': {'id': 'Caldera-no-preamble', 'deprecated': False},
|
| 130 |
+
'catharon': {'id': 'Catharon', 'deprecated': False},
|
| 131 |
+
'catosl-1.1': {'id': 'CATOSL-1.1', 'deprecated': False},
|
| 132 |
+
'cc-by-1.0': {'id': 'CC-BY-1.0', 'deprecated': False},
|
| 133 |
+
'cc-by-2.0': {'id': 'CC-BY-2.0', 'deprecated': False},
|
| 134 |
+
'cc-by-2.5': {'id': 'CC-BY-2.5', 'deprecated': False},
|
| 135 |
+
'cc-by-2.5-au': {'id': 'CC-BY-2.5-AU', 'deprecated': False},
|
| 136 |
+
'cc-by-3.0': {'id': 'CC-BY-3.0', 'deprecated': False},
|
| 137 |
+
'cc-by-3.0-at': {'id': 'CC-BY-3.0-AT', 'deprecated': False},
|
| 138 |
+
'cc-by-3.0-au': {'id': 'CC-BY-3.0-AU', 'deprecated': False},
|
| 139 |
+
'cc-by-3.0-de': {'id': 'CC-BY-3.0-DE', 'deprecated': False},
|
| 140 |
+
'cc-by-3.0-igo': {'id': 'CC-BY-3.0-IGO', 'deprecated': False},
|
| 141 |
+
'cc-by-3.0-nl': {'id': 'CC-BY-3.0-NL', 'deprecated': False},
|
| 142 |
+
'cc-by-3.0-us': {'id': 'CC-BY-3.0-US', 'deprecated': False},
|
| 143 |
+
'cc-by-4.0': {'id': 'CC-BY-4.0', 'deprecated': False},
|
| 144 |
+
'cc-by-nc-1.0': {'id': 'CC-BY-NC-1.0', 'deprecated': False},
|
| 145 |
+
'cc-by-nc-2.0': {'id': 'CC-BY-NC-2.0', 'deprecated': False},
|
| 146 |
+
'cc-by-nc-2.5': {'id': 'CC-BY-NC-2.5', 'deprecated': False},
|
| 147 |
+
'cc-by-nc-3.0': {'id': 'CC-BY-NC-3.0', 'deprecated': False},
|
| 148 |
+
'cc-by-nc-3.0-de': {'id': 'CC-BY-NC-3.0-DE', 'deprecated': False},
|
| 149 |
+
'cc-by-nc-4.0': {'id': 'CC-BY-NC-4.0', 'deprecated': False},
|
| 150 |
+
'cc-by-nc-nd-1.0': {'id': 'CC-BY-NC-ND-1.0', 'deprecated': False},
|
| 151 |
+
'cc-by-nc-nd-2.0': {'id': 'CC-BY-NC-ND-2.0', 'deprecated': False},
|
| 152 |
+
'cc-by-nc-nd-2.5': {'id': 'CC-BY-NC-ND-2.5', 'deprecated': False},
|
| 153 |
+
'cc-by-nc-nd-3.0': {'id': 'CC-BY-NC-ND-3.0', 'deprecated': False},
|
| 154 |
+
'cc-by-nc-nd-3.0-de': {'id': 'CC-BY-NC-ND-3.0-DE', 'deprecated': False},
|
| 155 |
+
'cc-by-nc-nd-3.0-igo': {'id': 'CC-BY-NC-ND-3.0-IGO', 'deprecated': False},
|
| 156 |
+
'cc-by-nc-nd-4.0': {'id': 'CC-BY-NC-ND-4.0', 'deprecated': False},
|
| 157 |
+
'cc-by-nc-sa-1.0': {'id': 'CC-BY-NC-SA-1.0', 'deprecated': False},
|
| 158 |
+
'cc-by-nc-sa-2.0': {'id': 'CC-BY-NC-SA-2.0', 'deprecated': False},
|
| 159 |
+
'cc-by-nc-sa-2.0-de': {'id': 'CC-BY-NC-SA-2.0-DE', 'deprecated': False},
|
| 160 |
+
'cc-by-nc-sa-2.0-fr': {'id': 'CC-BY-NC-SA-2.0-FR', 'deprecated': False},
|
| 161 |
+
'cc-by-nc-sa-2.0-uk': {'id': 'CC-BY-NC-SA-2.0-UK', 'deprecated': False},
|
| 162 |
+
'cc-by-nc-sa-2.5': {'id': 'CC-BY-NC-SA-2.5', 'deprecated': False},
|
| 163 |
+
'cc-by-nc-sa-3.0': {'id': 'CC-BY-NC-SA-3.0', 'deprecated': False},
|
| 164 |
+
'cc-by-nc-sa-3.0-de': {'id': 'CC-BY-NC-SA-3.0-DE', 'deprecated': False},
|
| 165 |
+
'cc-by-nc-sa-3.0-igo': {'id': 'CC-BY-NC-SA-3.0-IGO', 'deprecated': False},
|
| 166 |
+
'cc-by-nc-sa-4.0': {'id': 'CC-BY-NC-SA-4.0', 'deprecated': False},
|
| 167 |
+
'cc-by-nd-1.0': {'id': 'CC-BY-ND-1.0', 'deprecated': False},
|
| 168 |
+
'cc-by-nd-2.0': {'id': 'CC-BY-ND-2.0', 'deprecated': False},
|
| 169 |
+
'cc-by-nd-2.5': {'id': 'CC-BY-ND-2.5', 'deprecated': False},
|
| 170 |
+
'cc-by-nd-3.0': {'id': 'CC-BY-ND-3.0', 'deprecated': False},
|
| 171 |
+
'cc-by-nd-3.0-de': {'id': 'CC-BY-ND-3.0-DE', 'deprecated': False},
|
| 172 |
+
'cc-by-nd-4.0': {'id': 'CC-BY-ND-4.0', 'deprecated': False},
|
| 173 |
+
'cc-by-sa-1.0': {'id': 'CC-BY-SA-1.0', 'deprecated': False},
|
| 174 |
+
'cc-by-sa-2.0': {'id': 'CC-BY-SA-2.0', 'deprecated': False},
|
| 175 |
+
'cc-by-sa-2.0-uk': {'id': 'CC-BY-SA-2.0-UK', 'deprecated': False},
|
| 176 |
+
'cc-by-sa-2.1-jp': {'id': 'CC-BY-SA-2.1-JP', 'deprecated': False},
|
| 177 |
+
'cc-by-sa-2.5': {'id': 'CC-BY-SA-2.5', 'deprecated': False},
|
| 178 |
+
'cc-by-sa-3.0': {'id': 'CC-BY-SA-3.0', 'deprecated': False},
|
| 179 |
+
'cc-by-sa-3.0-at': {'id': 'CC-BY-SA-3.0-AT', 'deprecated': False},
|
| 180 |
+
'cc-by-sa-3.0-de': {'id': 'CC-BY-SA-3.0-DE', 'deprecated': False},
|
| 181 |
+
'cc-by-sa-3.0-igo': {'id': 'CC-BY-SA-3.0-IGO', 'deprecated': False},
|
| 182 |
+
'cc-by-sa-4.0': {'id': 'CC-BY-SA-4.0', 'deprecated': False},
|
| 183 |
+
'cc-pddc': {'id': 'CC-PDDC', 'deprecated': False},
|
| 184 |
+
'cc-pdm-1.0': {'id': 'CC-PDM-1.0', 'deprecated': False},
|
| 185 |
+
'cc-sa-1.0': {'id': 'CC-SA-1.0', 'deprecated': False},
|
| 186 |
+
'cc0-1.0': {'id': 'CC0-1.0', 'deprecated': False},
|
| 187 |
+
'cddl-1.0': {'id': 'CDDL-1.0', 'deprecated': False},
|
| 188 |
+
'cddl-1.1': {'id': 'CDDL-1.1', 'deprecated': False},
|
| 189 |
+
'cdl-1.0': {'id': 'CDL-1.0', 'deprecated': False},
|
| 190 |
+
'cdla-permissive-1.0': {'id': 'CDLA-Permissive-1.0', 'deprecated': False},
|
| 191 |
+
'cdla-permissive-2.0': {'id': 'CDLA-Permissive-2.0', 'deprecated': False},
|
| 192 |
+
'cdla-sharing-1.0': {'id': 'CDLA-Sharing-1.0', 'deprecated': False},
|
| 193 |
+
'cecill-1.0': {'id': 'CECILL-1.0', 'deprecated': False},
|
| 194 |
+
'cecill-1.1': {'id': 'CECILL-1.1', 'deprecated': False},
|
| 195 |
+
'cecill-2.0': {'id': 'CECILL-2.0', 'deprecated': False},
|
| 196 |
+
'cecill-2.1': {'id': 'CECILL-2.1', 'deprecated': False},
|
| 197 |
+
'cecill-b': {'id': 'CECILL-B', 'deprecated': False},
|
| 198 |
+
'cecill-c': {'id': 'CECILL-C', 'deprecated': False},
|
| 199 |
+
'cern-ohl-1.1': {'id': 'CERN-OHL-1.1', 'deprecated': False},
|
| 200 |
+
'cern-ohl-1.2': {'id': 'CERN-OHL-1.2', 'deprecated': False},
|
| 201 |
+
'cern-ohl-p-2.0': {'id': 'CERN-OHL-P-2.0', 'deprecated': False},
|
| 202 |
+
'cern-ohl-s-2.0': {'id': 'CERN-OHL-S-2.0', 'deprecated': False},
|
| 203 |
+
'cern-ohl-w-2.0': {'id': 'CERN-OHL-W-2.0', 'deprecated': False},
|
| 204 |
+
'cfitsio': {'id': 'CFITSIO', 'deprecated': False},
|
| 205 |
+
'check-cvs': {'id': 'check-cvs', 'deprecated': False},
|
| 206 |
+
'checkmk': {'id': 'checkmk', 'deprecated': False},
|
| 207 |
+
'clartistic': {'id': 'ClArtistic', 'deprecated': False},
|
| 208 |
+
'clips': {'id': 'Clips', 'deprecated': False},
|
| 209 |
+
'cmu-mach': {'id': 'CMU-Mach', 'deprecated': False},
|
| 210 |
+
'cmu-mach-nodoc': {'id': 'CMU-Mach-nodoc', 'deprecated': False},
|
| 211 |
+
'cnri-jython': {'id': 'CNRI-Jython', 'deprecated': False},
|
| 212 |
+
'cnri-python': {'id': 'CNRI-Python', 'deprecated': False},
|
| 213 |
+
'cnri-python-gpl-compatible': {'id': 'CNRI-Python-GPL-Compatible', 'deprecated': False},
|
| 214 |
+
'coil-1.0': {'id': 'COIL-1.0', 'deprecated': False},
|
| 215 |
+
'community-spec-1.0': {'id': 'Community-Spec-1.0', 'deprecated': False},
|
| 216 |
+
'condor-1.1': {'id': 'Condor-1.1', 'deprecated': False},
|
| 217 |
+
'copyleft-next-0.3.0': {'id': 'copyleft-next-0.3.0', 'deprecated': False},
|
| 218 |
+
'copyleft-next-0.3.1': {'id': 'copyleft-next-0.3.1', 'deprecated': False},
|
| 219 |
+
'cornell-lossless-jpeg': {'id': 'Cornell-Lossless-JPEG', 'deprecated': False},
|
| 220 |
+
'cpal-1.0': {'id': 'CPAL-1.0', 'deprecated': False},
|
| 221 |
+
'cpl-1.0': {'id': 'CPL-1.0', 'deprecated': False},
|
| 222 |
+
'cpol-1.02': {'id': 'CPOL-1.02', 'deprecated': False},
|
| 223 |
+
'cronyx': {'id': 'Cronyx', 'deprecated': False},
|
| 224 |
+
'crossword': {'id': 'Crossword', 'deprecated': False},
|
| 225 |
+
'cryptoswift': {'id': 'CryptoSwift', 'deprecated': False},
|
| 226 |
+
'crystalstacker': {'id': 'CrystalStacker', 'deprecated': False},
|
| 227 |
+
'cua-opl-1.0': {'id': 'CUA-OPL-1.0', 'deprecated': False},
|
| 228 |
+
'cube': {'id': 'Cube', 'deprecated': False},
|
| 229 |
+
'curl': {'id': 'curl', 'deprecated': False},
|
| 230 |
+
'cve-tou': {'id': 'cve-tou', 'deprecated': False},
|
| 231 |
+
'd-fsl-1.0': {'id': 'D-FSL-1.0', 'deprecated': False},
|
| 232 |
+
'dec-3-clause': {'id': 'DEC-3-Clause', 'deprecated': False},
|
| 233 |
+
'diffmark': {'id': 'diffmark', 'deprecated': False},
|
| 234 |
+
'dl-de-by-2.0': {'id': 'DL-DE-BY-2.0', 'deprecated': False},
|
| 235 |
+
'dl-de-zero-2.0': {'id': 'DL-DE-ZERO-2.0', 'deprecated': False},
|
| 236 |
+
'doc': {'id': 'DOC', 'deprecated': False},
|
| 237 |
+
'docbook-dtd': {'id': 'DocBook-DTD', 'deprecated': False},
|
| 238 |
+
'docbook-schema': {'id': 'DocBook-Schema', 'deprecated': False},
|
| 239 |
+
'docbook-stylesheet': {'id': 'DocBook-Stylesheet', 'deprecated': False},
|
| 240 |
+
'docbook-xml': {'id': 'DocBook-XML', 'deprecated': False},
|
| 241 |
+
'dotseqn': {'id': 'Dotseqn', 'deprecated': False},
|
| 242 |
+
'drl-1.0': {'id': 'DRL-1.0', 'deprecated': False},
|
| 243 |
+
'drl-1.1': {'id': 'DRL-1.1', 'deprecated': False},
|
| 244 |
+
'dsdp': {'id': 'DSDP', 'deprecated': False},
|
| 245 |
+
'dtoa': {'id': 'dtoa', 'deprecated': False},
|
| 246 |
+
'dvipdfm': {'id': 'dvipdfm', 'deprecated': False},
|
| 247 |
+
'ecl-1.0': {'id': 'ECL-1.0', 'deprecated': False},
|
| 248 |
+
'ecl-2.0': {'id': 'ECL-2.0', 'deprecated': False},
|
| 249 |
+
'ecos-2.0': {'id': 'eCos-2.0', 'deprecated': True},
|
| 250 |
+
'efl-1.0': {'id': 'EFL-1.0', 'deprecated': False},
|
| 251 |
+
'efl-2.0': {'id': 'EFL-2.0', 'deprecated': False},
|
| 252 |
+
'egenix': {'id': 'eGenix', 'deprecated': False},
|
| 253 |
+
'elastic-2.0': {'id': 'Elastic-2.0', 'deprecated': False},
|
| 254 |
+
'entessa': {'id': 'Entessa', 'deprecated': False},
|
| 255 |
+
'epics': {'id': 'EPICS', 'deprecated': False},
|
| 256 |
+
'epl-1.0': {'id': 'EPL-1.0', 'deprecated': False},
|
| 257 |
+
'epl-2.0': {'id': 'EPL-2.0', 'deprecated': False},
|
| 258 |
+
'erlpl-1.1': {'id': 'ErlPL-1.1', 'deprecated': False},
|
| 259 |
+
'etalab-2.0': {'id': 'etalab-2.0', 'deprecated': False},
|
| 260 |
+
'eudatagrid': {'id': 'EUDatagrid', 'deprecated': False},
|
| 261 |
+
'eupl-1.0': {'id': 'EUPL-1.0', 'deprecated': False},
|
| 262 |
+
'eupl-1.1': {'id': 'EUPL-1.1', 'deprecated': False},
|
| 263 |
+
'eupl-1.2': {'id': 'EUPL-1.2', 'deprecated': False},
|
| 264 |
+
'eurosym': {'id': 'Eurosym', 'deprecated': False},
|
| 265 |
+
'fair': {'id': 'Fair', 'deprecated': False},
|
| 266 |
+
'fbm': {'id': 'FBM', 'deprecated': False},
|
| 267 |
+
'fdk-aac': {'id': 'FDK-AAC', 'deprecated': False},
|
| 268 |
+
'ferguson-twofish': {'id': 'Ferguson-Twofish', 'deprecated': False},
|
| 269 |
+
'frameworx-1.0': {'id': 'Frameworx-1.0', 'deprecated': False},
|
| 270 |
+
'freebsd-doc': {'id': 'FreeBSD-DOC', 'deprecated': False},
|
| 271 |
+
'freeimage': {'id': 'FreeImage', 'deprecated': False},
|
| 272 |
+
'fsfap': {'id': 'FSFAP', 'deprecated': False},
|
| 273 |
+
'fsfap-no-warranty-disclaimer': {'id': 'FSFAP-no-warranty-disclaimer', 'deprecated': False},
|
| 274 |
+
'fsful': {'id': 'FSFUL', 'deprecated': False},
|
| 275 |
+
'fsfullr': {'id': 'FSFULLR', 'deprecated': False},
|
| 276 |
+
'fsfullrsd': {'id': 'FSFULLRSD', 'deprecated': False},
|
| 277 |
+
'fsfullrwd': {'id': 'FSFULLRWD', 'deprecated': False},
|
| 278 |
+
'fsl-1.1-alv2': {'id': 'FSL-1.1-ALv2', 'deprecated': False},
|
| 279 |
+
'fsl-1.1-mit': {'id': 'FSL-1.1-MIT', 'deprecated': False},
|
| 280 |
+
'ftl': {'id': 'FTL', 'deprecated': False},
|
| 281 |
+
'furuseth': {'id': 'Furuseth', 'deprecated': False},
|
| 282 |
+
'fwlw': {'id': 'fwlw', 'deprecated': False},
|
| 283 |
+
'game-programming-gems': {'id': 'Game-Programming-Gems', 'deprecated': False},
|
| 284 |
+
'gcr-docs': {'id': 'GCR-docs', 'deprecated': False},
|
| 285 |
+
'gd': {'id': 'GD', 'deprecated': False},
|
| 286 |
+
'generic-xts': {'id': 'generic-xts', 'deprecated': False},
|
| 287 |
+
'gfdl-1.1': {'id': 'GFDL-1.1', 'deprecated': True},
|
| 288 |
+
'gfdl-1.1-invariants-only': {'id': 'GFDL-1.1-invariants-only', 'deprecated': False},
|
| 289 |
+
'gfdl-1.1-invariants-or-later': {'id': 'GFDL-1.1-invariants-or-later', 'deprecated': False},
|
| 290 |
+
'gfdl-1.1-no-invariants-only': {'id': 'GFDL-1.1-no-invariants-only', 'deprecated': False},
|
| 291 |
+
'gfdl-1.1-no-invariants-or-later': {'id': 'GFDL-1.1-no-invariants-or-later', 'deprecated': False},
|
| 292 |
+
'gfdl-1.1-only': {'id': 'GFDL-1.1-only', 'deprecated': False},
|
| 293 |
+
'gfdl-1.1-or-later': {'id': 'GFDL-1.1-or-later', 'deprecated': False},
|
| 294 |
+
'gfdl-1.2': {'id': 'GFDL-1.2', 'deprecated': True},
|
| 295 |
+
'gfdl-1.2-invariants-only': {'id': 'GFDL-1.2-invariants-only', 'deprecated': False},
|
| 296 |
+
'gfdl-1.2-invariants-or-later': {'id': 'GFDL-1.2-invariants-or-later', 'deprecated': False},
|
| 297 |
+
'gfdl-1.2-no-invariants-only': {'id': 'GFDL-1.2-no-invariants-only', 'deprecated': False},
|
| 298 |
+
'gfdl-1.2-no-invariants-or-later': {'id': 'GFDL-1.2-no-invariants-or-later', 'deprecated': False},
|
| 299 |
+
'gfdl-1.2-only': {'id': 'GFDL-1.2-only', 'deprecated': False},
|
| 300 |
+
'gfdl-1.2-or-later': {'id': 'GFDL-1.2-or-later', 'deprecated': False},
|
| 301 |
+
'gfdl-1.3': {'id': 'GFDL-1.3', 'deprecated': True},
|
| 302 |
+
'gfdl-1.3-invariants-only': {'id': 'GFDL-1.3-invariants-only', 'deprecated': False},
|
| 303 |
+
'gfdl-1.3-invariants-or-later': {'id': 'GFDL-1.3-invariants-or-later', 'deprecated': False},
|
| 304 |
+
'gfdl-1.3-no-invariants-only': {'id': 'GFDL-1.3-no-invariants-only', 'deprecated': False},
|
| 305 |
+
'gfdl-1.3-no-invariants-or-later': {'id': 'GFDL-1.3-no-invariants-or-later', 'deprecated': False},
|
| 306 |
+
'gfdl-1.3-only': {'id': 'GFDL-1.3-only', 'deprecated': False},
|
| 307 |
+
'gfdl-1.3-or-later': {'id': 'GFDL-1.3-or-later', 'deprecated': False},
|
| 308 |
+
'giftware': {'id': 'Giftware', 'deprecated': False},
|
| 309 |
+
'gl2ps': {'id': 'GL2PS', 'deprecated': False},
|
| 310 |
+
'glide': {'id': 'Glide', 'deprecated': False},
|
| 311 |
+
'glulxe': {'id': 'Glulxe', 'deprecated': False},
|
| 312 |
+
'glwtpl': {'id': 'GLWTPL', 'deprecated': False},
|
| 313 |
+
'gnuplot': {'id': 'gnuplot', 'deprecated': False},
|
| 314 |
+
'gpl-1.0': {'id': 'GPL-1.0', 'deprecated': True},
|
| 315 |
+
'gpl-1.0+': {'id': 'GPL-1.0+', 'deprecated': True},
|
| 316 |
+
'gpl-1.0-only': {'id': 'GPL-1.0-only', 'deprecated': False},
|
| 317 |
+
'gpl-1.0-or-later': {'id': 'GPL-1.0-or-later', 'deprecated': False},
|
| 318 |
+
'gpl-2.0': {'id': 'GPL-2.0', 'deprecated': True},
|
| 319 |
+
'gpl-2.0+': {'id': 'GPL-2.0+', 'deprecated': True},
|
| 320 |
+
'gpl-2.0-only': {'id': 'GPL-2.0-only', 'deprecated': False},
|
| 321 |
+
'gpl-2.0-or-later': {'id': 'GPL-2.0-or-later', 'deprecated': False},
|
| 322 |
+
'gpl-2.0-with-autoconf-exception': {'id': 'GPL-2.0-with-autoconf-exception', 'deprecated': True},
|
| 323 |
+
'gpl-2.0-with-bison-exception': {'id': 'GPL-2.0-with-bison-exception', 'deprecated': True},
|
| 324 |
+
'gpl-2.0-with-classpath-exception': {'id': 'GPL-2.0-with-classpath-exception', 'deprecated': True},
|
| 325 |
+
'gpl-2.0-with-font-exception': {'id': 'GPL-2.0-with-font-exception', 'deprecated': True},
|
| 326 |
+
'gpl-2.0-with-gcc-exception': {'id': 'GPL-2.0-with-GCC-exception', 'deprecated': True},
|
| 327 |
+
'gpl-3.0': {'id': 'GPL-3.0', 'deprecated': True},
|
| 328 |
+
'gpl-3.0+': {'id': 'GPL-3.0+', 'deprecated': True},
|
| 329 |
+
'gpl-3.0-only': {'id': 'GPL-3.0-only', 'deprecated': False},
|
| 330 |
+
'gpl-3.0-or-later': {'id': 'GPL-3.0-or-later', 'deprecated': False},
|
| 331 |
+
'gpl-3.0-with-autoconf-exception': {'id': 'GPL-3.0-with-autoconf-exception', 'deprecated': True},
|
| 332 |
+
'gpl-3.0-with-gcc-exception': {'id': 'GPL-3.0-with-GCC-exception', 'deprecated': True},
|
| 333 |
+
'graphics-gems': {'id': 'Graphics-Gems', 'deprecated': False},
|
| 334 |
+
'gsoap-1.3b': {'id': 'gSOAP-1.3b', 'deprecated': False},
|
| 335 |
+
'gtkbook': {'id': 'gtkbook', 'deprecated': False},
|
| 336 |
+
'gutmann': {'id': 'Gutmann', 'deprecated': False},
|
| 337 |
+
'haskellreport': {'id': 'HaskellReport', 'deprecated': False},
|
| 338 |
+
'hdf5': {'id': 'HDF5', 'deprecated': False},
|
| 339 |
+
'hdparm': {'id': 'hdparm', 'deprecated': False},
|
| 340 |
+
'hidapi': {'id': 'HIDAPI', 'deprecated': False},
|
| 341 |
+
'hippocratic-2.1': {'id': 'Hippocratic-2.1', 'deprecated': False},
|
| 342 |
+
'hp-1986': {'id': 'HP-1986', 'deprecated': False},
|
| 343 |
+
'hp-1989': {'id': 'HP-1989', 'deprecated': False},
|
| 344 |
+
'hpnd': {'id': 'HPND', 'deprecated': False},
|
| 345 |
+
'hpnd-dec': {'id': 'HPND-DEC', 'deprecated': False},
|
| 346 |
+
'hpnd-doc': {'id': 'HPND-doc', 'deprecated': False},
|
| 347 |
+
'hpnd-doc-sell': {'id': 'HPND-doc-sell', 'deprecated': False},
|
| 348 |
+
'hpnd-export-us': {'id': 'HPND-export-US', 'deprecated': False},
|
| 349 |
+
'hpnd-export-us-acknowledgement': {'id': 'HPND-export-US-acknowledgement', 'deprecated': False},
|
| 350 |
+
'hpnd-export-us-modify': {'id': 'HPND-export-US-modify', 'deprecated': False},
|
| 351 |
+
'hpnd-export2-us': {'id': 'HPND-export2-US', 'deprecated': False},
|
| 352 |
+
'hpnd-fenneberg-livingston': {'id': 'HPND-Fenneberg-Livingston', 'deprecated': False},
|
| 353 |
+
'hpnd-inria-imag': {'id': 'HPND-INRIA-IMAG', 'deprecated': False},
|
| 354 |
+
'hpnd-intel': {'id': 'HPND-Intel', 'deprecated': False},
|
| 355 |
+
'hpnd-kevlin-henney': {'id': 'HPND-Kevlin-Henney', 'deprecated': False},
|
| 356 |
+
'hpnd-markus-kuhn': {'id': 'HPND-Markus-Kuhn', 'deprecated': False},
|
| 357 |
+
'hpnd-merchantability-variant': {'id': 'HPND-merchantability-variant', 'deprecated': False},
|
| 358 |
+
'hpnd-mit-disclaimer': {'id': 'HPND-MIT-disclaimer', 'deprecated': False},
|
| 359 |
+
'hpnd-netrek': {'id': 'HPND-Netrek', 'deprecated': False},
|
| 360 |
+
'hpnd-pbmplus': {'id': 'HPND-Pbmplus', 'deprecated': False},
|
| 361 |
+
'hpnd-sell-mit-disclaimer-xserver': {'id': 'HPND-sell-MIT-disclaimer-xserver', 'deprecated': False},
|
| 362 |
+
'hpnd-sell-regexpr': {'id': 'HPND-sell-regexpr', 'deprecated': False},
|
| 363 |
+
'hpnd-sell-variant': {'id': 'HPND-sell-variant', 'deprecated': False},
|
| 364 |
+
'hpnd-sell-variant-mit-disclaimer': {'id': 'HPND-sell-variant-MIT-disclaimer', 'deprecated': False},
|
| 365 |
+
'hpnd-sell-variant-mit-disclaimer-rev': {'id': 'HPND-sell-variant-MIT-disclaimer-rev', 'deprecated': False},
|
| 366 |
+
'hpnd-uc': {'id': 'HPND-UC', 'deprecated': False},
|
| 367 |
+
'hpnd-uc-export-us': {'id': 'HPND-UC-export-US', 'deprecated': False},
|
| 368 |
+
'htmltidy': {'id': 'HTMLTIDY', 'deprecated': False},
|
| 369 |
+
'ibm-pibs': {'id': 'IBM-pibs', 'deprecated': False},
|
| 370 |
+
'icu': {'id': 'ICU', 'deprecated': False},
|
| 371 |
+
'iec-code-components-eula': {'id': 'IEC-Code-Components-EULA', 'deprecated': False},
|
| 372 |
+
'ijg': {'id': 'IJG', 'deprecated': False},
|
| 373 |
+
'ijg-short': {'id': 'IJG-short', 'deprecated': False},
|
| 374 |
+
'imagemagick': {'id': 'ImageMagick', 'deprecated': False},
|
| 375 |
+
'imatix': {'id': 'iMatix', 'deprecated': False},
|
| 376 |
+
'imlib2': {'id': 'Imlib2', 'deprecated': False},
|
| 377 |
+
'info-zip': {'id': 'Info-ZIP', 'deprecated': False},
|
| 378 |
+
'inner-net-2.0': {'id': 'Inner-Net-2.0', 'deprecated': False},
|
| 379 |
+
'innosetup': {'id': 'InnoSetup', 'deprecated': False},
|
| 380 |
+
'intel': {'id': 'Intel', 'deprecated': False},
|
| 381 |
+
'intel-acpi': {'id': 'Intel-ACPI', 'deprecated': False},
|
| 382 |
+
'interbase-1.0': {'id': 'Interbase-1.0', 'deprecated': False},
|
| 383 |
+
'ipa': {'id': 'IPA', 'deprecated': False},
|
| 384 |
+
'ipl-1.0': {'id': 'IPL-1.0', 'deprecated': False},
|
| 385 |
+
'isc': {'id': 'ISC', 'deprecated': False},
|
| 386 |
+
'isc-veillard': {'id': 'ISC-Veillard', 'deprecated': False},
|
| 387 |
+
'jam': {'id': 'Jam', 'deprecated': False},
|
| 388 |
+
'jasper-2.0': {'id': 'JasPer-2.0', 'deprecated': False},
|
| 389 |
+
'jove': {'id': 'jove', 'deprecated': False},
|
| 390 |
+
'jpl-image': {'id': 'JPL-image', 'deprecated': False},
|
| 391 |
+
'jpnic': {'id': 'JPNIC', 'deprecated': False},
|
| 392 |
+
'json': {'id': 'JSON', 'deprecated': False},
|
| 393 |
+
'kastrup': {'id': 'Kastrup', 'deprecated': False},
|
| 394 |
+
'kazlib': {'id': 'Kazlib', 'deprecated': False},
|
| 395 |
+
'knuth-ctan': {'id': 'Knuth-CTAN', 'deprecated': False},
|
| 396 |
+
'lal-1.2': {'id': 'LAL-1.2', 'deprecated': False},
|
| 397 |
+
'lal-1.3': {'id': 'LAL-1.3', 'deprecated': False},
|
| 398 |
+
'latex2e': {'id': 'Latex2e', 'deprecated': False},
|
| 399 |
+
'latex2e-translated-notice': {'id': 'Latex2e-translated-notice', 'deprecated': False},
|
| 400 |
+
'leptonica': {'id': 'Leptonica', 'deprecated': False},
|
| 401 |
+
'lgpl-2.0': {'id': 'LGPL-2.0', 'deprecated': True},
|
| 402 |
+
'lgpl-2.0+': {'id': 'LGPL-2.0+', 'deprecated': True},
|
| 403 |
+
'lgpl-2.0-only': {'id': 'LGPL-2.0-only', 'deprecated': False},
|
| 404 |
+
'lgpl-2.0-or-later': {'id': 'LGPL-2.0-or-later', 'deprecated': False},
|
| 405 |
+
'lgpl-2.1': {'id': 'LGPL-2.1', 'deprecated': True},
|
| 406 |
+
'lgpl-2.1+': {'id': 'LGPL-2.1+', 'deprecated': True},
|
| 407 |
+
'lgpl-2.1-only': {'id': 'LGPL-2.1-only', 'deprecated': False},
|
| 408 |
+
'lgpl-2.1-or-later': {'id': 'LGPL-2.1-or-later', 'deprecated': False},
|
| 409 |
+
'lgpl-3.0': {'id': 'LGPL-3.0', 'deprecated': True},
|
| 410 |
+
'lgpl-3.0+': {'id': 'LGPL-3.0+', 'deprecated': True},
|
| 411 |
+
'lgpl-3.0-only': {'id': 'LGPL-3.0-only', 'deprecated': False},
|
| 412 |
+
'lgpl-3.0-or-later': {'id': 'LGPL-3.0-or-later', 'deprecated': False},
|
| 413 |
+
'lgpllr': {'id': 'LGPLLR', 'deprecated': False},
|
| 414 |
+
'libpng': {'id': 'Libpng', 'deprecated': False},
|
| 415 |
+
'libpng-1.6.35': {'id': 'libpng-1.6.35', 'deprecated': False},
|
| 416 |
+
'libpng-2.0': {'id': 'libpng-2.0', 'deprecated': False},
|
| 417 |
+
'libselinux-1.0': {'id': 'libselinux-1.0', 'deprecated': False},
|
| 418 |
+
'libtiff': {'id': 'libtiff', 'deprecated': False},
|
| 419 |
+
'libutil-david-nugent': {'id': 'libutil-David-Nugent', 'deprecated': False},
|
| 420 |
+
'liliq-p-1.1': {'id': 'LiLiQ-P-1.1', 'deprecated': False},
|
| 421 |
+
'liliq-r-1.1': {'id': 'LiLiQ-R-1.1', 'deprecated': False},
|
| 422 |
+
'liliq-rplus-1.1': {'id': 'LiLiQ-Rplus-1.1', 'deprecated': False},
|
| 423 |
+
'linux-man-pages-1-para': {'id': 'Linux-man-pages-1-para', 'deprecated': False},
|
| 424 |
+
'linux-man-pages-copyleft': {'id': 'Linux-man-pages-copyleft', 'deprecated': False},
|
| 425 |
+
'linux-man-pages-copyleft-2-para': {'id': 'Linux-man-pages-copyleft-2-para', 'deprecated': False},
|
| 426 |
+
'linux-man-pages-copyleft-var': {'id': 'Linux-man-pages-copyleft-var', 'deprecated': False},
|
| 427 |
+
'linux-openib': {'id': 'Linux-OpenIB', 'deprecated': False},
|
| 428 |
+
'loop': {'id': 'LOOP', 'deprecated': False},
|
| 429 |
+
'lpd-document': {'id': 'LPD-document', 'deprecated': False},
|
| 430 |
+
'lpl-1.0': {'id': 'LPL-1.0', 'deprecated': False},
|
| 431 |
+
'lpl-1.02': {'id': 'LPL-1.02', 'deprecated': False},
|
| 432 |
+
'lppl-1.0': {'id': 'LPPL-1.0', 'deprecated': False},
|
| 433 |
+
'lppl-1.1': {'id': 'LPPL-1.1', 'deprecated': False},
|
| 434 |
+
'lppl-1.2': {'id': 'LPPL-1.2', 'deprecated': False},
|
| 435 |
+
'lppl-1.3a': {'id': 'LPPL-1.3a', 'deprecated': False},
|
| 436 |
+
'lppl-1.3c': {'id': 'LPPL-1.3c', 'deprecated': False},
|
| 437 |
+
'lsof': {'id': 'lsof', 'deprecated': False},
|
| 438 |
+
'lucida-bitmap-fonts': {'id': 'Lucida-Bitmap-Fonts', 'deprecated': False},
|
| 439 |
+
'lzma-sdk-9.11-to-9.20': {'id': 'LZMA-SDK-9.11-to-9.20', 'deprecated': False},
|
| 440 |
+
'lzma-sdk-9.22': {'id': 'LZMA-SDK-9.22', 'deprecated': False},
|
| 441 |
+
'mackerras-3-clause': {'id': 'Mackerras-3-Clause', 'deprecated': False},
|
| 442 |
+
'mackerras-3-clause-acknowledgment': {'id': 'Mackerras-3-Clause-acknowledgment', 'deprecated': False},
|
| 443 |
+
'magaz': {'id': 'magaz', 'deprecated': False},
|
| 444 |
+
'mailprio': {'id': 'mailprio', 'deprecated': False},
|
| 445 |
+
'makeindex': {'id': 'MakeIndex', 'deprecated': False},
|
| 446 |
+
'man2html': {'id': 'man2html', 'deprecated': False},
|
| 447 |
+
'martin-birgmeier': {'id': 'Martin-Birgmeier', 'deprecated': False},
|
| 448 |
+
'mcphee-slideshow': {'id': 'McPhee-slideshow', 'deprecated': False},
|
| 449 |
+
'metamail': {'id': 'metamail', 'deprecated': False},
|
| 450 |
+
'minpack': {'id': 'Minpack', 'deprecated': False},
|
| 451 |
+
'mips': {'id': 'MIPS', 'deprecated': False},
|
| 452 |
+
'miros': {'id': 'MirOS', 'deprecated': False},
|
| 453 |
+
'mit': {'id': 'MIT', 'deprecated': False},
|
| 454 |
+
'mit-0': {'id': 'MIT-0', 'deprecated': False},
|
| 455 |
+
'mit-advertising': {'id': 'MIT-advertising', 'deprecated': False},
|
| 456 |
+
'mit-click': {'id': 'MIT-Click', 'deprecated': False},
|
| 457 |
+
'mit-cmu': {'id': 'MIT-CMU', 'deprecated': False},
|
| 458 |
+
'mit-enna': {'id': 'MIT-enna', 'deprecated': False},
|
| 459 |
+
'mit-feh': {'id': 'MIT-feh', 'deprecated': False},
|
| 460 |
+
'mit-festival': {'id': 'MIT-Festival', 'deprecated': False},
|
| 461 |
+
'mit-khronos-old': {'id': 'MIT-Khronos-old', 'deprecated': False},
|
| 462 |
+
'mit-modern-variant': {'id': 'MIT-Modern-Variant', 'deprecated': False},
|
| 463 |
+
'mit-open-group': {'id': 'MIT-open-group', 'deprecated': False},
|
| 464 |
+
'mit-testregex': {'id': 'MIT-testregex', 'deprecated': False},
|
| 465 |
+
'mit-wu': {'id': 'MIT-Wu', 'deprecated': False},
|
| 466 |
+
'mitnfa': {'id': 'MITNFA', 'deprecated': False},
|
| 467 |
+
'mmixware': {'id': 'MMIXware', 'deprecated': False},
|
| 468 |
+
'motosoto': {'id': 'Motosoto', 'deprecated': False},
|
| 469 |
+
'mpeg-ssg': {'id': 'MPEG-SSG', 'deprecated': False},
|
| 470 |
+
'mpi-permissive': {'id': 'mpi-permissive', 'deprecated': False},
|
| 471 |
+
'mpich2': {'id': 'mpich2', 'deprecated': False},
|
| 472 |
+
'mpl-1.0': {'id': 'MPL-1.0', 'deprecated': False},
|
| 473 |
+
'mpl-1.1': {'id': 'MPL-1.1', 'deprecated': False},
|
| 474 |
+
'mpl-2.0': {'id': 'MPL-2.0', 'deprecated': False},
|
| 475 |
+
'mpl-2.0-no-copyleft-exception': {'id': 'MPL-2.0-no-copyleft-exception', 'deprecated': False},
|
| 476 |
+
'mplus': {'id': 'mplus', 'deprecated': False},
|
| 477 |
+
'ms-lpl': {'id': 'MS-LPL', 'deprecated': False},
|
| 478 |
+
'ms-pl': {'id': 'MS-PL', 'deprecated': False},
|
| 479 |
+
'ms-rl': {'id': 'MS-RL', 'deprecated': False},
|
| 480 |
+
'mtll': {'id': 'MTLL', 'deprecated': False},
|
| 481 |
+
'mulanpsl-1.0': {'id': 'MulanPSL-1.0', 'deprecated': False},
|
| 482 |
+
'mulanpsl-2.0': {'id': 'MulanPSL-2.0', 'deprecated': False},
|
| 483 |
+
'multics': {'id': 'Multics', 'deprecated': False},
|
| 484 |
+
'mup': {'id': 'Mup', 'deprecated': False},
|
| 485 |
+
'naist-2003': {'id': 'NAIST-2003', 'deprecated': False},
|
| 486 |
+
'nasa-1.3': {'id': 'NASA-1.3', 'deprecated': False},
|
| 487 |
+
'naumen': {'id': 'Naumen', 'deprecated': False},
|
| 488 |
+
'nbpl-1.0': {'id': 'NBPL-1.0', 'deprecated': False},
|
| 489 |
+
'ncbi-pd': {'id': 'NCBI-PD', 'deprecated': False},
|
| 490 |
+
'ncgl-uk-2.0': {'id': 'NCGL-UK-2.0', 'deprecated': False},
|
| 491 |
+
'ncl': {'id': 'NCL', 'deprecated': False},
|
| 492 |
+
'ncsa': {'id': 'NCSA', 'deprecated': False},
|
| 493 |
+
'net-snmp': {'id': 'Net-SNMP', 'deprecated': True},
|
| 494 |
+
'netcdf': {'id': 'NetCDF', 'deprecated': False},
|
| 495 |
+
'newsletr': {'id': 'Newsletr', 'deprecated': False},
|
| 496 |
+
'ngpl': {'id': 'NGPL', 'deprecated': False},
|
| 497 |
+
'ngrep': {'id': 'ngrep', 'deprecated': False},
|
| 498 |
+
'nicta-1.0': {'id': 'NICTA-1.0', 'deprecated': False},
|
| 499 |
+
'nist-pd': {'id': 'NIST-PD', 'deprecated': False},
|
| 500 |
+
'nist-pd-fallback': {'id': 'NIST-PD-fallback', 'deprecated': False},
|
| 501 |
+
'nist-software': {'id': 'NIST-Software', 'deprecated': False},
|
| 502 |
+
'nlod-1.0': {'id': 'NLOD-1.0', 'deprecated': False},
|
| 503 |
+
'nlod-2.0': {'id': 'NLOD-2.0', 'deprecated': False},
|
| 504 |
+
'nlpl': {'id': 'NLPL', 'deprecated': False},
|
| 505 |
+
'nokia': {'id': 'Nokia', 'deprecated': False},
|
| 506 |
+
'nosl': {'id': 'NOSL', 'deprecated': False},
|
| 507 |
+
'noweb': {'id': 'Noweb', 'deprecated': False},
|
| 508 |
+
'npl-1.0': {'id': 'NPL-1.0', 'deprecated': False},
|
| 509 |
+
'npl-1.1': {'id': 'NPL-1.1', 'deprecated': False},
|
| 510 |
+
'nposl-3.0': {'id': 'NPOSL-3.0', 'deprecated': False},
|
| 511 |
+
'nrl': {'id': 'NRL', 'deprecated': False},
|
| 512 |
+
'ntia-pd': {'id': 'NTIA-PD', 'deprecated': False},
|
| 513 |
+
'ntp': {'id': 'NTP', 'deprecated': False},
|
| 514 |
+
'ntp-0': {'id': 'NTP-0', 'deprecated': False},
|
| 515 |
+
'nunit': {'id': 'Nunit', 'deprecated': True},
|
| 516 |
+
'o-uda-1.0': {'id': 'O-UDA-1.0', 'deprecated': False},
|
| 517 |
+
'oar': {'id': 'OAR', 'deprecated': False},
|
| 518 |
+
'occt-pl': {'id': 'OCCT-PL', 'deprecated': False},
|
| 519 |
+
'oclc-2.0': {'id': 'OCLC-2.0', 'deprecated': False},
|
| 520 |
+
'odbl-1.0': {'id': 'ODbL-1.0', 'deprecated': False},
|
| 521 |
+
'odc-by-1.0': {'id': 'ODC-By-1.0', 'deprecated': False},
|
| 522 |
+
'offis': {'id': 'OFFIS', 'deprecated': False},
|
| 523 |
+
'ofl-1.0': {'id': 'OFL-1.0', 'deprecated': False},
|
| 524 |
+
'ofl-1.0-no-rfn': {'id': 'OFL-1.0-no-RFN', 'deprecated': False},
|
| 525 |
+
'ofl-1.0-rfn': {'id': 'OFL-1.0-RFN', 'deprecated': False},
|
| 526 |
+
'ofl-1.1': {'id': 'OFL-1.1', 'deprecated': False},
|
| 527 |
+
'ofl-1.1-no-rfn': {'id': 'OFL-1.1-no-RFN', 'deprecated': False},
|
| 528 |
+
'ofl-1.1-rfn': {'id': 'OFL-1.1-RFN', 'deprecated': False},
|
| 529 |
+
'ogc-1.0': {'id': 'OGC-1.0', 'deprecated': False},
|
| 530 |
+
'ogdl-taiwan-1.0': {'id': 'OGDL-Taiwan-1.0', 'deprecated': False},
|
| 531 |
+
'ogl-canada-2.0': {'id': 'OGL-Canada-2.0', 'deprecated': False},
|
| 532 |
+
'ogl-uk-1.0': {'id': 'OGL-UK-1.0', 'deprecated': False},
|
| 533 |
+
'ogl-uk-2.0': {'id': 'OGL-UK-2.0', 'deprecated': False},
|
| 534 |
+
'ogl-uk-3.0': {'id': 'OGL-UK-3.0', 'deprecated': False},
|
| 535 |
+
'ogtsl': {'id': 'OGTSL', 'deprecated': False},
|
| 536 |
+
'oldap-1.1': {'id': 'OLDAP-1.1', 'deprecated': False},
|
| 537 |
+
'oldap-1.2': {'id': 'OLDAP-1.2', 'deprecated': False},
|
| 538 |
+
'oldap-1.3': {'id': 'OLDAP-1.3', 'deprecated': False},
|
| 539 |
+
'oldap-1.4': {'id': 'OLDAP-1.4', 'deprecated': False},
|
| 540 |
+
'oldap-2.0': {'id': 'OLDAP-2.0', 'deprecated': False},
|
| 541 |
+
'oldap-2.0.1': {'id': 'OLDAP-2.0.1', 'deprecated': False},
|
| 542 |
+
'oldap-2.1': {'id': 'OLDAP-2.1', 'deprecated': False},
|
| 543 |
+
'oldap-2.2': {'id': 'OLDAP-2.2', 'deprecated': False},
|
| 544 |
+
'oldap-2.2.1': {'id': 'OLDAP-2.2.1', 'deprecated': False},
|
| 545 |
+
'oldap-2.2.2': {'id': 'OLDAP-2.2.2', 'deprecated': False},
|
| 546 |
+
'oldap-2.3': {'id': 'OLDAP-2.3', 'deprecated': False},
|
| 547 |
+
'oldap-2.4': {'id': 'OLDAP-2.4', 'deprecated': False},
|
| 548 |
+
'oldap-2.5': {'id': 'OLDAP-2.5', 'deprecated': False},
|
| 549 |
+
'oldap-2.6': {'id': 'OLDAP-2.6', 'deprecated': False},
|
| 550 |
+
'oldap-2.7': {'id': 'OLDAP-2.7', 'deprecated': False},
|
| 551 |
+
'oldap-2.8': {'id': 'OLDAP-2.8', 'deprecated': False},
|
| 552 |
+
'olfl-1.3': {'id': 'OLFL-1.3', 'deprecated': False},
|
| 553 |
+
'oml': {'id': 'OML', 'deprecated': False},
|
| 554 |
+
'openpbs-2.3': {'id': 'OpenPBS-2.3', 'deprecated': False},
|
| 555 |
+
'openssl': {'id': 'OpenSSL', 'deprecated': False},
|
| 556 |
+
'openssl-standalone': {'id': 'OpenSSL-standalone', 'deprecated': False},
|
| 557 |
+
'openvision': {'id': 'OpenVision', 'deprecated': False},
|
| 558 |
+
'opl-1.0': {'id': 'OPL-1.0', 'deprecated': False},
|
| 559 |
+
'opl-uk-3.0': {'id': 'OPL-UK-3.0', 'deprecated': False},
|
| 560 |
+
'opubl-1.0': {'id': 'OPUBL-1.0', 'deprecated': False},
|
| 561 |
+
'oset-pl-2.1': {'id': 'OSET-PL-2.1', 'deprecated': False},
|
| 562 |
+
'osl-1.0': {'id': 'OSL-1.0', 'deprecated': False},
|
| 563 |
+
'osl-1.1': {'id': 'OSL-1.1', 'deprecated': False},
|
| 564 |
+
'osl-2.0': {'id': 'OSL-2.0', 'deprecated': False},
|
| 565 |
+
'osl-2.1': {'id': 'OSL-2.1', 'deprecated': False},
|
| 566 |
+
'osl-3.0': {'id': 'OSL-3.0', 'deprecated': False},
|
| 567 |
+
'padl': {'id': 'PADL', 'deprecated': False},
|
| 568 |
+
'parity-6.0.0': {'id': 'Parity-6.0.0', 'deprecated': False},
|
| 569 |
+
'parity-7.0.0': {'id': 'Parity-7.0.0', 'deprecated': False},
|
| 570 |
+
'pddl-1.0': {'id': 'PDDL-1.0', 'deprecated': False},
|
| 571 |
+
'php-3.0': {'id': 'PHP-3.0', 'deprecated': False},
|
| 572 |
+
'php-3.01': {'id': 'PHP-3.01', 'deprecated': False},
|
| 573 |
+
'pixar': {'id': 'Pixar', 'deprecated': False},
|
| 574 |
+
'pkgconf': {'id': 'pkgconf', 'deprecated': False},
|
| 575 |
+
'plexus': {'id': 'Plexus', 'deprecated': False},
|
| 576 |
+
'pnmstitch': {'id': 'pnmstitch', 'deprecated': False},
|
| 577 |
+
'polyform-noncommercial-1.0.0': {'id': 'PolyForm-Noncommercial-1.0.0', 'deprecated': False},
|
| 578 |
+
'polyform-small-business-1.0.0': {'id': 'PolyForm-Small-Business-1.0.0', 'deprecated': False},
|
| 579 |
+
'postgresql': {'id': 'PostgreSQL', 'deprecated': False},
|
| 580 |
+
'ppl': {'id': 'PPL', 'deprecated': False},
|
| 581 |
+
'psf-2.0': {'id': 'PSF-2.0', 'deprecated': False},
|
| 582 |
+
'psfrag': {'id': 'psfrag', 'deprecated': False},
|
| 583 |
+
'psutils': {'id': 'psutils', 'deprecated': False},
|
| 584 |
+
'python-2.0': {'id': 'Python-2.0', 'deprecated': False},
|
| 585 |
+
'python-2.0.1': {'id': 'Python-2.0.1', 'deprecated': False},
|
| 586 |
+
'python-ldap': {'id': 'python-ldap', 'deprecated': False},
|
| 587 |
+
'qhull': {'id': 'Qhull', 'deprecated': False},
|
| 588 |
+
'qpl-1.0': {'id': 'QPL-1.0', 'deprecated': False},
|
| 589 |
+
'qpl-1.0-inria-2004': {'id': 'QPL-1.0-INRIA-2004', 'deprecated': False},
|
| 590 |
+
'radvd': {'id': 'radvd', 'deprecated': False},
|
| 591 |
+
'rdisc': {'id': 'Rdisc', 'deprecated': False},
|
| 592 |
+
'rhecos-1.1': {'id': 'RHeCos-1.1', 'deprecated': False},
|
| 593 |
+
'rpl-1.1': {'id': 'RPL-1.1', 'deprecated': False},
|
| 594 |
+
'rpl-1.5': {'id': 'RPL-1.5', 'deprecated': False},
|
| 595 |
+
'rpsl-1.0': {'id': 'RPSL-1.0', 'deprecated': False},
|
| 596 |
+
'rsa-md': {'id': 'RSA-MD', 'deprecated': False},
|
| 597 |
+
'rscpl': {'id': 'RSCPL', 'deprecated': False},
|
| 598 |
+
'ruby': {'id': 'Ruby', 'deprecated': False},
|
| 599 |
+
'ruby-pty': {'id': 'Ruby-pty', 'deprecated': False},
|
| 600 |
+
'sax-pd': {'id': 'SAX-PD', 'deprecated': False},
|
| 601 |
+
'sax-pd-2.0': {'id': 'SAX-PD-2.0', 'deprecated': False},
|
| 602 |
+
'saxpath': {'id': 'Saxpath', 'deprecated': False},
|
| 603 |
+
'scea': {'id': 'SCEA', 'deprecated': False},
|
| 604 |
+
'schemereport': {'id': 'SchemeReport', 'deprecated': False},
|
| 605 |
+
'sendmail': {'id': 'Sendmail', 'deprecated': False},
|
| 606 |
+
'sendmail-8.23': {'id': 'Sendmail-8.23', 'deprecated': False},
|
| 607 |
+
'sendmail-open-source-1.1': {'id': 'Sendmail-Open-Source-1.1', 'deprecated': False},
|
| 608 |
+
'sgi-b-1.0': {'id': 'SGI-B-1.0', 'deprecated': False},
|
| 609 |
+
'sgi-b-1.1': {'id': 'SGI-B-1.1', 'deprecated': False},
|
| 610 |
+
'sgi-b-2.0': {'id': 'SGI-B-2.0', 'deprecated': False},
|
| 611 |
+
'sgi-opengl': {'id': 'SGI-OpenGL', 'deprecated': False},
|
| 612 |
+
'sgp4': {'id': 'SGP4', 'deprecated': False},
|
| 613 |
+
'shl-0.5': {'id': 'SHL-0.5', 'deprecated': False},
|
| 614 |
+
'shl-0.51': {'id': 'SHL-0.51', 'deprecated': False},
|
| 615 |
+
'simpl-2.0': {'id': 'SimPL-2.0', 'deprecated': False},
|
| 616 |
+
'sissl': {'id': 'SISSL', 'deprecated': False},
|
| 617 |
+
'sissl-1.2': {'id': 'SISSL-1.2', 'deprecated': False},
|
| 618 |
+
'sl': {'id': 'SL', 'deprecated': False},
|
| 619 |
+
'sleepycat': {'id': 'Sleepycat', 'deprecated': False},
|
| 620 |
+
'smail-gpl': {'id': 'SMAIL-GPL', 'deprecated': False},
|
| 621 |
+
'smlnj': {'id': 'SMLNJ', 'deprecated': False},
|
| 622 |
+
'smppl': {'id': 'SMPPL', 'deprecated': False},
|
| 623 |
+
'snia': {'id': 'SNIA', 'deprecated': False},
|
| 624 |
+
'snprintf': {'id': 'snprintf', 'deprecated': False},
|
| 625 |
+
'sofa': {'id': 'SOFA', 'deprecated': False},
|
| 626 |
+
'softsurfer': {'id': 'softSurfer', 'deprecated': False},
|
| 627 |
+
'soundex': {'id': 'Soundex', 'deprecated': False},
|
| 628 |
+
'spencer-86': {'id': 'Spencer-86', 'deprecated': False},
|
| 629 |
+
'spencer-94': {'id': 'Spencer-94', 'deprecated': False},
|
| 630 |
+
'spencer-99': {'id': 'Spencer-99', 'deprecated': False},
|
| 631 |
+
'spl-1.0': {'id': 'SPL-1.0', 'deprecated': False},
|
| 632 |
+
'ssh-keyscan': {'id': 'ssh-keyscan', 'deprecated': False},
|
| 633 |
+
'ssh-openssh': {'id': 'SSH-OpenSSH', 'deprecated': False},
|
| 634 |
+
'ssh-short': {'id': 'SSH-short', 'deprecated': False},
|
| 635 |
+
'ssleay-standalone': {'id': 'SSLeay-standalone', 'deprecated': False},
|
| 636 |
+
'sspl-1.0': {'id': 'SSPL-1.0', 'deprecated': False},
|
| 637 |
+
'standardml-nj': {'id': 'StandardML-NJ', 'deprecated': True},
|
| 638 |
+
'sugarcrm-1.1.3': {'id': 'SugarCRM-1.1.3', 'deprecated': False},
|
| 639 |
+
'sul-1.0': {'id': 'SUL-1.0', 'deprecated': False},
|
| 640 |
+
'sun-ppp': {'id': 'Sun-PPP', 'deprecated': False},
|
| 641 |
+
'sun-ppp-2000': {'id': 'Sun-PPP-2000', 'deprecated': False},
|
| 642 |
+
'sunpro': {'id': 'SunPro', 'deprecated': False},
|
| 643 |
+
'swl': {'id': 'SWL', 'deprecated': False},
|
| 644 |
+
'swrule': {'id': 'swrule', 'deprecated': False},
|
| 645 |
+
'symlinks': {'id': 'Symlinks', 'deprecated': False},
|
| 646 |
+
'tapr-ohl-1.0': {'id': 'TAPR-OHL-1.0', 'deprecated': False},
|
| 647 |
+
'tcl': {'id': 'TCL', 'deprecated': False},
|
| 648 |
+
'tcp-wrappers': {'id': 'TCP-wrappers', 'deprecated': False},
|
| 649 |
+
'termreadkey': {'id': 'TermReadKey', 'deprecated': False},
|
| 650 |
+
'tgppl-1.0': {'id': 'TGPPL-1.0', 'deprecated': False},
|
| 651 |
+
'thirdeye': {'id': 'ThirdEye', 'deprecated': False},
|
| 652 |
+
'threeparttable': {'id': 'threeparttable', 'deprecated': False},
|
| 653 |
+
'tmate': {'id': 'TMate', 'deprecated': False},
|
| 654 |
+
'torque-1.1': {'id': 'TORQUE-1.1', 'deprecated': False},
|
| 655 |
+
'tosl': {'id': 'TOSL', 'deprecated': False},
|
| 656 |
+
'tpdl': {'id': 'TPDL', 'deprecated': False},
|
| 657 |
+
'tpl-1.0': {'id': 'TPL-1.0', 'deprecated': False},
|
| 658 |
+
'trustedqsl': {'id': 'TrustedQSL', 'deprecated': False},
|
| 659 |
+
'ttwl': {'id': 'TTWL', 'deprecated': False},
|
| 660 |
+
'ttyp0': {'id': 'TTYP0', 'deprecated': False},
|
| 661 |
+
'tu-berlin-1.0': {'id': 'TU-Berlin-1.0', 'deprecated': False},
|
| 662 |
+
'tu-berlin-2.0': {'id': 'TU-Berlin-2.0', 'deprecated': False},
|
| 663 |
+
'ubuntu-font-1.0': {'id': 'Ubuntu-font-1.0', 'deprecated': False},
|
| 664 |
+
'ucar': {'id': 'UCAR', 'deprecated': False},
|
| 665 |
+
'ucl-1.0': {'id': 'UCL-1.0', 'deprecated': False},
|
| 666 |
+
'ulem': {'id': 'ulem', 'deprecated': False},
|
| 667 |
+
'umich-merit': {'id': 'UMich-Merit', 'deprecated': False},
|
| 668 |
+
'unicode-3.0': {'id': 'Unicode-3.0', 'deprecated': False},
|
| 669 |
+
'unicode-dfs-2015': {'id': 'Unicode-DFS-2015', 'deprecated': False},
|
| 670 |
+
'unicode-dfs-2016': {'id': 'Unicode-DFS-2016', 'deprecated': False},
|
| 671 |
+
'unicode-tou': {'id': 'Unicode-TOU', 'deprecated': False},
|
| 672 |
+
'unixcrypt': {'id': 'UnixCrypt', 'deprecated': False},
|
| 673 |
+
'unlicense': {'id': 'Unlicense', 'deprecated': False},
|
| 674 |
+
'unlicense-libtelnet': {'id': 'Unlicense-libtelnet', 'deprecated': False},
|
| 675 |
+
'unlicense-libwhirlpool': {'id': 'Unlicense-libwhirlpool', 'deprecated': False},
|
| 676 |
+
'upl-1.0': {'id': 'UPL-1.0', 'deprecated': False},
|
| 677 |
+
'urt-rle': {'id': 'URT-RLE', 'deprecated': False},
|
| 678 |
+
'vim': {'id': 'Vim', 'deprecated': False},
|
| 679 |
+
'vostrom': {'id': 'VOSTROM', 'deprecated': False},
|
| 680 |
+
'vsl-1.0': {'id': 'VSL-1.0', 'deprecated': False},
|
| 681 |
+
'w3c': {'id': 'W3C', 'deprecated': False},
|
| 682 |
+
'w3c-19980720': {'id': 'W3C-19980720', 'deprecated': False},
|
| 683 |
+
'w3c-20150513': {'id': 'W3C-20150513', 'deprecated': False},
|
| 684 |
+
'w3m': {'id': 'w3m', 'deprecated': False},
|
| 685 |
+
'watcom-1.0': {'id': 'Watcom-1.0', 'deprecated': False},
|
| 686 |
+
'widget-workshop': {'id': 'Widget-Workshop', 'deprecated': False},
|
| 687 |
+
'wsuipa': {'id': 'Wsuipa', 'deprecated': False},
|
| 688 |
+
'wtfpl': {'id': 'WTFPL', 'deprecated': False},
|
| 689 |
+
'wwl': {'id': 'wwl', 'deprecated': False},
|
| 690 |
+
'wxwindows': {'id': 'wxWindows', 'deprecated': True},
|
| 691 |
+
'x11': {'id': 'X11', 'deprecated': False},
|
| 692 |
+
'x11-distribute-modifications-variant': {'id': 'X11-distribute-modifications-variant', 'deprecated': False},
|
| 693 |
+
'x11-swapped': {'id': 'X11-swapped', 'deprecated': False},
|
| 694 |
+
'xdebug-1.03': {'id': 'Xdebug-1.03', 'deprecated': False},
|
| 695 |
+
'xerox': {'id': 'Xerox', 'deprecated': False},
|
| 696 |
+
'xfig': {'id': 'Xfig', 'deprecated': False},
|
| 697 |
+
'xfree86-1.1': {'id': 'XFree86-1.1', 'deprecated': False},
|
| 698 |
+
'xinetd': {'id': 'xinetd', 'deprecated': False},
|
| 699 |
+
'xkeyboard-config-zinoviev': {'id': 'xkeyboard-config-Zinoviev', 'deprecated': False},
|
| 700 |
+
'xlock': {'id': 'xlock', 'deprecated': False},
|
| 701 |
+
'xnet': {'id': 'Xnet', 'deprecated': False},
|
| 702 |
+
'xpp': {'id': 'xpp', 'deprecated': False},
|
| 703 |
+
'xskat': {'id': 'XSkat', 'deprecated': False},
|
| 704 |
+
'xzoom': {'id': 'xzoom', 'deprecated': False},
|
| 705 |
+
'ypl-1.0': {'id': 'YPL-1.0', 'deprecated': False},
|
| 706 |
+
'ypl-1.1': {'id': 'YPL-1.1', 'deprecated': False},
|
| 707 |
+
'zed': {'id': 'Zed', 'deprecated': False},
|
| 708 |
+
'zeeff': {'id': 'Zeeff', 'deprecated': False},
|
| 709 |
+
'zend-2.0': {'id': 'Zend-2.0', 'deprecated': False},
|
| 710 |
+
'zimbra-1.3': {'id': 'Zimbra-1.3', 'deprecated': False},
|
| 711 |
+
'zimbra-1.4': {'id': 'Zimbra-1.4', 'deprecated': False},
|
| 712 |
+
'zlib': {'id': 'Zlib', 'deprecated': False},
|
| 713 |
+
'zlib-acknowledgement': {'id': 'zlib-acknowledgement', 'deprecated': False},
|
| 714 |
+
'zpl-1.1': {'id': 'ZPL-1.1', 'deprecated': False},
|
| 715 |
+
'zpl-2.0': {'id': 'ZPL-2.0', 'deprecated': False},
|
| 716 |
+
'zpl-2.1': {'id': 'ZPL-2.1', 'deprecated': False},
|
| 717 |
+
}
|
| 718 |
+
|
| 719 |
+
EXCEPTIONS: dict[str, SPDXException] = {
|
| 720 |
+
'389-exception': {'id': '389-exception', 'deprecated': False},
|
| 721 |
+
'asterisk-exception': {'id': 'Asterisk-exception', 'deprecated': False},
|
| 722 |
+
'asterisk-linking-protocols-exception': {'id': 'Asterisk-linking-protocols-exception', 'deprecated': False},
|
| 723 |
+
'autoconf-exception-2.0': {'id': 'Autoconf-exception-2.0', 'deprecated': False},
|
| 724 |
+
'autoconf-exception-3.0': {'id': 'Autoconf-exception-3.0', 'deprecated': False},
|
| 725 |
+
'autoconf-exception-generic': {'id': 'Autoconf-exception-generic', 'deprecated': False},
|
| 726 |
+
'autoconf-exception-generic-3.0': {'id': 'Autoconf-exception-generic-3.0', 'deprecated': False},
|
| 727 |
+
'autoconf-exception-macro': {'id': 'Autoconf-exception-macro', 'deprecated': False},
|
| 728 |
+
'bison-exception-1.24': {'id': 'Bison-exception-1.24', 'deprecated': False},
|
| 729 |
+
'bison-exception-2.2': {'id': 'Bison-exception-2.2', 'deprecated': False},
|
| 730 |
+
'bootloader-exception': {'id': 'Bootloader-exception', 'deprecated': False},
|
| 731 |
+
'cgal-linking-exception': {'id': 'CGAL-linking-exception', 'deprecated': False},
|
| 732 |
+
'classpath-exception-2.0': {'id': 'Classpath-exception-2.0', 'deprecated': False},
|
| 733 |
+
'clisp-exception-2.0': {'id': 'CLISP-exception-2.0', 'deprecated': False},
|
| 734 |
+
'cryptsetup-openssl-exception': {'id': 'cryptsetup-OpenSSL-exception', 'deprecated': False},
|
| 735 |
+
'digia-qt-lgpl-exception-1.1': {'id': 'Digia-Qt-LGPL-exception-1.1', 'deprecated': False},
|
| 736 |
+
'digirule-foss-exception': {'id': 'DigiRule-FOSS-exception', 'deprecated': False},
|
| 737 |
+
'ecos-exception-2.0': {'id': 'eCos-exception-2.0', 'deprecated': False},
|
| 738 |
+
'erlang-otp-linking-exception': {'id': 'erlang-otp-linking-exception', 'deprecated': False},
|
| 739 |
+
'fawkes-runtime-exception': {'id': 'Fawkes-Runtime-exception', 'deprecated': False},
|
| 740 |
+
'fltk-exception': {'id': 'FLTK-exception', 'deprecated': False},
|
| 741 |
+
'fmt-exception': {'id': 'fmt-exception', 'deprecated': False},
|
| 742 |
+
'font-exception-2.0': {'id': 'Font-exception-2.0', 'deprecated': False},
|
| 743 |
+
'freertos-exception-2.0': {'id': 'freertos-exception-2.0', 'deprecated': False},
|
| 744 |
+
'gcc-exception-2.0': {'id': 'GCC-exception-2.0', 'deprecated': False},
|
| 745 |
+
'gcc-exception-2.0-note': {'id': 'GCC-exception-2.0-note', 'deprecated': False},
|
| 746 |
+
'gcc-exception-3.1': {'id': 'GCC-exception-3.1', 'deprecated': False},
|
| 747 |
+
'gmsh-exception': {'id': 'Gmsh-exception', 'deprecated': False},
|
| 748 |
+
'gnat-exception': {'id': 'GNAT-exception', 'deprecated': False},
|
| 749 |
+
'gnome-examples-exception': {'id': 'GNOME-examples-exception', 'deprecated': False},
|
| 750 |
+
'gnu-compiler-exception': {'id': 'GNU-compiler-exception', 'deprecated': False},
|
| 751 |
+
'gnu-javamail-exception': {'id': 'gnu-javamail-exception', 'deprecated': False},
|
| 752 |
+
'gpl-3.0-389-ds-base-exception': {'id': 'GPL-3.0-389-ds-base-exception', 'deprecated': False},
|
| 753 |
+
'gpl-3.0-interface-exception': {'id': 'GPL-3.0-interface-exception', 'deprecated': False},
|
| 754 |
+
'gpl-3.0-linking-exception': {'id': 'GPL-3.0-linking-exception', 'deprecated': False},
|
| 755 |
+
'gpl-3.0-linking-source-exception': {'id': 'GPL-3.0-linking-source-exception', 'deprecated': False},
|
| 756 |
+
'gpl-cc-1.0': {'id': 'GPL-CC-1.0', 'deprecated': False},
|
| 757 |
+
'gstreamer-exception-2005': {'id': 'GStreamer-exception-2005', 'deprecated': False},
|
| 758 |
+
'gstreamer-exception-2008': {'id': 'GStreamer-exception-2008', 'deprecated': False},
|
| 759 |
+
'harbour-exception': {'id': 'harbour-exception', 'deprecated': False},
|
| 760 |
+
'i2p-gpl-java-exception': {'id': 'i2p-gpl-java-exception', 'deprecated': False},
|
| 761 |
+
'independent-modules-exception': {'id': 'Independent-modules-exception', 'deprecated': False},
|
| 762 |
+
'kicad-libraries-exception': {'id': 'KiCad-libraries-exception', 'deprecated': False},
|
| 763 |
+
'lgpl-3.0-linking-exception': {'id': 'LGPL-3.0-linking-exception', 'deprecated': False},
|
| 764 |
+
'libpri-openh323-exception': {'id': 'libpri-OpenH323-exception', 'deprecated': False},
|
| 765 |
+
'libtool-exception': {'id': 'Libtool-exception', 'deprecated': False},
|
| 766 |
+
'linux-syscall-note': {'id': 'Linux-syscall-note', 'deprecated': False},
|
| 767 |
+
'llgpl': {'id': 'LLGPL', 'deprecated': False},
|
| 768 |
+
'llvm-exception': {'id': 'LLVM-exception', 'deprecated': False},
|
| 769 |
+
'lzma-exception': {'id': 'LZMA-exception', 'deprecated': False},
|
| 770 |
+
'mif-exception': {'id': 'mif-exception', 'deprecated': False},
|
| 771 |
+
'mxml-exception': {'id': 'mxml-exception', 'deprecated': False},
|
| 772 |
+
'nokia-qt-exception-1.1': {'id': 'Nokia-Qt-exception-1.1', 'deprecated': True},
|
| 773 |
+
'ocaml-lgpl-linking-exception': {'id': 'OCaml-LGPL-linking-exception', 'deprecated': False},
|
| 774 |
+
'occt-exception-1.0': {'id': 'OCCT-exception-1.0', 'deprecated': False},
|
| 775 |
+
'openjdk-assembly-exception-1.0': {'id': 'OpenJDK-assembly-exception-1.0', 'deprecated': False},
|
| 776 |
+
'openvpn-openssl-exception': {'id': 'openvpn-openssl-exception', 'deprecated': False},
|
| 777 |
+
'pcre2-exception': {'id': 'PCRE2-exception', 'deprecated': False},
|
| 778 |
+
'polyparse-exception': {'id': 'polyparse-exception', 'deprecated': False},
|
| 779 |
+
'ps-or-pdf-font-exception-20170817': {'id': 'PS-or-PDF-font-exception-20170817', 'deprecated': False},
|
| 780 |
+
'qpl-1.0-inria-2004-exception': {'id': 'QPL-1.0-INRIA-2004-exception', 'deprecated': False},
|
| 781 |
+
'qt-gpl-exception-1.0': {'id': 'Qt-GPL-exception-1.0', 'deprecated': False},
|
| 782 |
+
'qt-lgpl-exception-1.1': {'id': 'Qt-LGPL-exception-1.1', 'deprecated': False},
|
| 783 |
+
'qwt-exception-1.0': {'id': 'Qwt-exception-1.0', 'deprecated': False},
|
| 784 |
+
'romic-exception': {'id': 'romic-exception', 'deprecated': False},
|
| 785 |
+
'rrdtool-floss-exception-2.0': {'id': 'RRDtool-FLOSS-exception-2.0', 'deprecated': False},
|
| 786 |
+
'sane-exception': {'id': 'SANE-exception', 'deprecated': False},
|
| 787 |
+
'shl-2.0': {'id': 'SHL-2.0', 'deprecated': False},
|
| 788 |
+
'shl-2.1': {'id': 'SHL-2.1', 'deprecated': False},
|
| 789 |
+
'stunnel-exception': {'id': 'stunnel-exception', 'deprecated': False},
|
| 790 |
+
'swi-exception': {'id': 'SWI-exception', 'deprecated': False},
|
| 791 |
+
'swift-exception': {'id': 'Swift-exception', 'deprecated': False},
|
| 792 |
+
'texinfo-exception': {'id': 'Texinfo-exception', 'deprecated': False},
|
| 793 |
+
'u-boot-exception-2.0': {'id': 'u-boot-exception-2.0', 'deprecated': False},
|
| 794 |
+
'ubdl-exception': {'id': 'UBDL-exception', 'deprecated': False},
|
| 795 |
+
'universal-foss-exception-1.0': {'id': 'Universal-FOSS-exception-1.0', 'deprecated': False},
|
| 796 |
+
'vsftpd-openssl-exception': {'id': 'vsftpd-openssl-exception', 'deprecated': False},
|
| 797 |
+
'wxwindows-exception-3.1': {'id': 'WxWindows-exception-3.1', 'deprecated': False},
|
| 798 |
+
'x11vnc-openssl-exception': {'id': 'x11vnc-openssl-exception', 'deprecated': False},
|
| 799 |
+
}
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/markers.py
ADDED
|
@@ -0,0 +1,492 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
|
| 5 |
+
from __future__ import annotations
|
| 6 |
+
|
| 7 |
+
import operator
|
| 8 |
+
import os
|
| 9 |
+
import platform
|
| 10 |
+
import sys
|
| 11 |
+
from typing import AbstractSet, Callable, Literal, Mapping, TypedDict, Union, cast
|
| 12 |
+
|
| 13 |
+
from ._parser import MarkerAtom, MarkerList, Op, Value, Variable
|
| 14 |
+
from ._parser import parse_marker as _parse_marker
|
| 15 |
+
from ._tokenizer import ParserSyntaxError
|
| 16 |
+
from .specifiers import InvalidSpecifier, Specifier
|
| 17 |
+
from .utils import canonicalize_name
|
| 18 |
+
|
| 19 |
+
__all__ = [
|
| 20 |
+
"Environment",
|
| 21 |
+
"EvaluateContext",
|
| 22 |
+
"InvalidMarker",
|
| 23 |
+
"Marker",
|
| 24 |
+
"UndefinedComparison",
|
| 25 |
+
"UndefinedEnvironmentName",
|
| 26 |
+
"default_environment",
|
| 27 |
+
]
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def __dir__() -> list[str]:
|
| 31 |
+
return __all__
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
Operator = Callable[[str, Union[str, AbstractSet[str]]], bool]
|
| 35 |
+
EvaluateContext = Literal["metadata", "lock_file", "requirement"]
|
| 36 |
+
"""A ``typing.Literal`` enumerating valid marker evaluation contexts.
|
| 37 |
+
|
| 38 |
+
Valid values for the ``context`` passed to :meth:`Marker.evaluate` are:
|
| 39 |
+
|
| 40 |
+
* ``"metadata"`` (for core metadata; default)
|
| 41 |
+
* ``"lock_file"`` (for lock files)
|
| 42 |
+
* ``"requirement"`` (i.e. all other situations)
|
| 43 |
+
"""
|
| 44 |
+
|
| 45 |
+
MARKERS_ALLOWING_SET = {"extras", "dependency_groups"}
|
| 46 |
+
MARKERS_REQUIRING_VERSION = {
|
| 47 |
+
"implementation_version",
|
| 48 |
+
"platform_release",
|
| 49 |
+
"python_full_version",
|
| 50 |
+
"python_version",
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
class InvalidMarker(ValueError):
|
| 55 |
+
"""Raised when attempting to create a :class:`Marker` from invalid input.
|
| 56 |
+
|
| 57 |
+
This error indicates that the given marker string does not conform to the
|
| 58 |
+
:ref:`specification of dependency specifiers <pypug:dependency-specifiers>`.
|
| 59 |
+
"""
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
class UndefinedComparison(ValueError):
|
| 63 |
+
"""Raised when evaluating an unsupported marker comparison.
|
| 64 |
+
|
| 65 |
+
This can happen when marker values are compared as versions but do not
|
| 66 |
+
conform to the :ref:`specification of version specifiers
|
| 67 |
+
<pypug:version-specifiers>`.
|
| 68 |
+
"""
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
class UndefinedEnvironmentName(ValueError):
|
| 72 |
+
"""Raised when evaluating a marker that references a missing environment key."""
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class Environment(TypedDict):
|
| 76 |
+
"""
|
| 77 |
+
A dictionary that represents a Python environment as captured by
|
| 78 |
+
:func:`default_environment`. All fields are required.
|
| 79 |
+
"""
|
| 80 |
+
|
| 81 |
+
implementation_name: str
|
| 82 |
+
"""The implementation's identifier, e.g. ``'cpython'``."""
|
| 83 |
+
|
| 84 |
+
implementation_version: str
|
| 85 |
+
"""
|
| 86 |
+
The implementation's version, e.g. ``'3.13.0a2'`` for CPython 3.13.0a2, or
|
| 87 |
+
``'7.3.13'`` for PyPy3.10 v7.3.13.
|
| 88 |
+
"""
|
| 89 |
+
|
| 90 |
+
os_name: str
|
| 91 |
+
"""
|
| 92 |
+
The value of :py:data:`os.name`. The name of the operating system dependent module
|
| 93 |
+
imported, e.g. ``'posix'``.
|
| 94 |
+
"""
|
| 95 |
+
|
| 96 |
+
platform_machine: str
|
| 97 |
+
"""
|
| 98 |
+
Returns the machine type, e.g. ``'i386'``.
|
| 99 |
+
|
| 100 |
+
An empty string if the value cannot be determined.
|
| 101 |
+
"""
|
| 102 |
+
|
| 103 |
+
platform_release: str
|
| 104 |
+
"""
|
| 105 |
+
The system's release, e.g. ``'2.2.0'`` or ``'NT'``.
|
| 106 |
+
|
| 107 |
+
An empty string if the value cannot be determined.
|
| 108 |
+
"""
|
| 109 |
+
|
| 110 |
+
platform_system: str
|
| 111 |
+
"""
|
| 112 |
+
The system/OS name, e.g. ``'Linux'``, ``'Windows'`` or ``'Java'``.
|
| 113 |
+
|
| 114 |
+
An empty string if the value cannot be determined.
|
| 115 |
+
"""
|
| 116 |
+
|
| 117 |
+
platform_version: str
|
| 118 |
+
"""
|
| 119 |
+
The system's release version, e.g. ``'#3 on degas'``.
|
| 120 |
+
|
| 121 |
+
An empty string if the value cannot be determined.
|
| 122 |
+
"""
|
| 123 |
+
|
| 124 |
+
python_full_version: str
|
| 125 |
+
"""
|
| 126 |
+
The Python version as string ``'major.minor.patchlevel'``.
|
| 127 |
+
|
| 128 |
+
Note that unlike the Python :py:data:`sys.version`, this value will always include
|
| 129 |
+
the patchlevel (it defaults to 0).
|
| 130 |
+
"""
|
| 131 |
+
|
| 132 |
+
platform_python_implementation: str
|
| 133 |
+
"""
|
| 134 |
+
A string identifying the Python implementation, e.g. ``'CPython'``.
|
| 135 |
+
"""
|
| 136 |
+
|
| 137 |
+
python_version: str
|
| 138 |
+
"""The Python version as string ``'major.minor'``."""
|
| 139 |
+
|
| 140 |
+
sys_platform: str
|
| 141 |
+
"""
|
| 142 |
+
This string contains a platform identifier that can be used to append
|
| 143 |
+
platform-specific components to :py:data:`sys.path`, for instance.
|
| 144 |
+
|
| 145 |
+
For Unix systems, except on Linux and AIX, this is the lowercased OS name as
|
| 146 |
+
returned by ``uname -s`` with the first part of the version as returned by
|
| 147 |
+
``uname -r`` appended, e.g. ``'sunos5'`` or ``'freebsd8'``, at the time when Python
|
| 148 |
+
was built.
|
| 149 |
+
"""
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def _normalize_extras(
|
| 153 |
+
result: MarkerList | MarkerAtom | str,
|
| 154 |
+
) -> MarkerList | MarkerAtom | str:
|
| 155 |
+
if not isinstance(result, tuple):
|
| 156 |
+
return result
|
| 157 |
+
|
| 158 |
+
lhs, op, rhs = result
|
| 159 |
+
if isinstance(lhs, Variable) and lhs.value == "extra":
|
| 160 |
+
normalized_extra = canonicalize_name(rhs.value)
|
| 161 |
+
rhs = Value(normalized_extra)
|
| 162 |
+
elif isinstance(rhs, Variable) and rhs.value == "extra":
|
| 163 |
+
normalized_extra = canonicalize_name(lhs.value)
|
| 164 |
+
lhs = Value(normalized_extra)
|
| 165 |
+
return lhs, op, rhs
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
def _normalize_extra_values(results: MarkerList) -> MarkerList:
|
| 169 |
+
"""
|
| 170 |
+
Normalize extra values.
|
| 171 |
+
"""
|
| 172 |
+
|
| 173 |
+
return [_normalize_extras(r) for r in results]
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def _format_marker(
|
| 177 |
+
marker: list[str] | MarkerAtom | str, first: bool | None = True
|
| 178 |
+
) -> str:
|
| 179 |
+
assert isinstance(marker, (list, tuple, str))
|
| 180 |
+
|
| 181 |
+
# Sometimes we have a structure like [[...]] which is a single item list
|
| 182 |
+
# where the single item is itself it's own list. In that case we want skip
|
| 183 |
+
# the rest of this function so that we don't get extraneous () on the
|
| 184 |
+
# outside.
|
| 185 |
+
if (
|
| 186 |
+
isinstance(marker, list)
|
| 187 |
+
and len(marker) == 1
|
| 188 |
+
and isinstance(marker[0], (list, tuple))
|
| 189 |
+
):
|
| 190 |
+
return _format_marker(marker[0])
|
| 191 |
+
|
| 192 |
+
if isinstance(marker, list):
|
| 193 |
+
inner = (_format_marker(m, first=False) for m in marker)
|
| 194 |
+
if first:
|
| 195 |
+
return " ".join(inner)
|
| 196 |
+
else:
|
| 197 |
+
return "(" + " ".join(inner) + ")"
|
| 198 |
+
elif isinstance(marker, tuple):
|
| 199 |
+
return " ".join([m.serialize() for m in marker])
|
| 200 |
+
else:
|
| 201 |
+
return marker
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
_operators: dict[str, Operator] = {
|
| 205 |
+
"in": lambda lhs, rhs: lhs in rhs,
|
| 206 |
+
"not in": lambda lhs, rhs: lhs not in rhs,
|
| 207 |
+
"<": lambda _lhs, _rhs: False,
|
| 208 |
+
"<=": operator.eq,
|
| 209 |
+
"==": operator.eq,
|
| 210 |
+
"!=": operator.ne,
|
| 211 |
+
">=": operator.eq,
|
| 212 |
+
">": lambda _lhs, _rhs: False,
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
def _eval_op(lhs: str, op: Op, rhs: str | AbstractSet[str], *, key: str) -> bool:
|
| 217 |
+
op_str = op.serialize()
|
| 218 |
+
if key in MARKERS_REQUIRING_VERSION:
|
| 219 |
+
try:
|
| 220 |
+
spec = Specifier(f"{op_str}{rhs}")
|
| 221 |
+
except InvalidSpecifier:
|
| 222 |
+
pass
|
| 223 |
+
else:
|
| 224 |
+
return spec.contains(lhs, prereleases=True)
|
| 225 |
+
|
| 226 |
+
oper: Operator | None = _operators.get(op_str)
|
| 227 |
+
if oper is None:
|
| 228 |
+
raise UndefinedComparison(f"Undefined {op!r} on {lhs!r} and {rhs!r}.")
|
| 229 |
+
|
| 230 |
+
return oper(lhs, rhs)
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
def _normalize(
|
| 234 |
+
lhs: str, rhs: str | AbstractSet[str], key: str
|
| 235 |
+
) -> tuple[str, str | AbstractSet[str]]:
|
| 236 |
+
# PEP 685 - Comparison of extra names for optional distribution dependencies
|
| 237 |
+
# https://peps.python.org/pep-0685/
|
| 238 |
+
# > When comparing extra names, tools MUST normalize the names being
|
| 239 |
+
# > compared using the semantics outlined in PEP 503 for names
|
| 240 |
+
if key == "extra":
|
| 241 |
+
assert isinstance(rhs, str), "extra value must be a string"
|
| 242 |
+
# Both sides are normalized at this point already
|
| 243 |
+
return (lhs, rhs)
|
| 244 |
+
if key in MARKERS_ALLOWING_SET:
|
| 245 |
+
if isinstance(rhs, str): # pragma: no cover
|
| 246 |
+
return (canonicalize_name(lhs), canonicalize_name(rhs))
|
| 247 |
+
else:
|
| 248 |
+
return (canonicalize_name(lhs), {canonicalize_name(v) for v in rhs})
|
| 249 |
+
|
| 250 |
+
# other environment markers don't have such standards
|
| 251 |
+
return lhs, rhs
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
def _evaluate_markers(
|
| 255 |
+
markers: MarkerList, environment: dict[str, str | AbstractSet[str]]
|
| 256 |
+
) -> bool:
|
| 257 |
+
groups: list[list[bool]] = [[]]
|
| 258 |
+
|
| 259 |
+
for marker in markers:
|
| 260 |
+
if isinstance(marker, list):
|
| 261 |
+
groups[-1].append(_evaluate_markers(marker, environment))
|
| 262 |
+
elif isinstance(marker, tuple):
|
| 263 |
+
lhs, op, rhs = marker
|
| 264 |
+
|
| 265 |
+
if isinstance(lhs, Variable):
|
| 266 |
+
environment_key = lhs.value
|
| 267 |
+
lhs_value = environment[environment_key]
|
| 268 |
+
rhs_value = rhs.value
|
| 269 |
+
else:
|
| 270 |
+
lhs_value = lhs.value
|
| 271 |
+
environment_key = rhs.value
|
| 272 |
+
rhs_value = environment[environment_key]
|
| 273 |
+
|
| 274 |
+
assert isinstance(lhs_value, str), "lhs must be a string"
|
| 275 |
+
lhs_value, rhs_value = _normalize(lhs_value, rhs_value, key=environment_key)
|
| 276 |
+
groups[-1].append(_eval_op(lhs_value, op, rhs_value, key=environment_key))
|
| 277 |
+
elif marker == "or":
|
| 278 |
+
groups.append([])
|
| 279 |
+
elif marker == "and":
|
| 280 |
+
pass
|
| 281 |
+
else: # pragma: nocover
|
| 282 |
+
raise TypeError(f"Unexpected marker {marker!r}")
|
| 283 |
+
|
| 284 |
+
return any(all(item) for item in groups)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
def _format_full_version(info: sys._version_info) -> str:
|
| 288 |
+
version = f"{info.major}.{info.minor}.{info.micro}"
|
| 289 |
+
kind = info.releaselevel
|
| 290 |
+
if kind != "final":
|
| 291 |
+
version += kind[0] + str(info.serial)
|
| 292 |
+
return version
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
def default_environment() -> Environment:
|
| 296 |
+
"""Return the default marker environment for the current Python process.
|
| 297 |
+
|
| 298 |
+
This is the base environment used by :meth:`Marker.evaluate`.
|
| 299 |
+
"""
|
| 300 |
+
iver = _format_full_version(sys.implementation.version)
|
| 301 |
+
implementation_name = sys.implementation.name
|
| 302 |
+
return {
|
| 303 |
+
"implementation_name": implementation_name,
|
| 304 |
+
"implementation_version": iver,
|
| 305 |
+
"os_name": os.name,
|
| 306 |
+
"platform_machine": platform.machine(),
|
| 307 |
+
"platform_release": platform.release(),
|
| 308 |
+
"platform_system": platform.system(),
|
| 309 |
+
"platform_version": platform.version(),
|
| 310 |
+
"python_full_version": platform.python_version(),
|
| 311 |
+
"platform_python_implementation": platform.python_implementation(),
|
| 312 |
+
"python_version": ".".join(platform.python_version_tuple()[:2]),
|
| 313 |
+
"sys_platform": sys.platform,
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
class Marker:
|
| 318 |
+
"""Represents a parsed dependency marker expression.
|
| 319 |
+
|
| 320 |
+
Marker expressions are parsed according to the
|
| 321 |
+
:ref:`specification of dependency specifiers <pypug:dependency-specifiers>`.
|
| 322 |
+
|
| 323 |
+
:param marker: The string representation of a marker expression.
|
| 324 |
+
:raises InvalidMarker: If ``marker`` cannot be parsed.
|
| 325 |
+
|
| 326 |
+
Instances are safe to serialize with :mod:`pickle`. They use a stable
|
| 327 |
+
format so the same pickle can be loaded in future packaging releases.
|
| 328 |
+
|
| 329 |
+
.. versionchanged:: 26.2
|
| 330 |
+
|
| 331 |
+
Added a stable pickle format. Pickles created with packaging 26.2+ can
|
| 332 |
+
be unpickled with future releases. Backward compatibility with pickles
|
| 333 |
+
from pip._vendor.packaging < 26.2 is supported but may be removed in a future
|
| 334 |
+
release.
|
| 335 |
+
"""
|
| 336 |
+
|
| 337 |
+
__slots__ = ("_markers",)
|
| 338 |
+
|
| 339 |
+
def __init__(self, marker: str) -> None:
|
| 340 |
+
# Note: We create a Marker object without calling this constructor in
|
| 341 |
+
# packaging.requirements.Requirement. If any additional logic is
|
| 342 |
+
# added here, make sure to mirror/adapt Requirement.
|
| 343 |
+
|
| 344 |
+
# If this fails and throws an error, the repr still expects _markers to
|
| 345 |
+
# be defined.
|
| 346 |
+
self._markers: MarkerList = []
|
| 347 |
+
|
| 348 |
+
try:
|
| 349 |
+
self._markers = _normalize_extra_values(_parse_marker(marker))
|
| 350 |
+
# The attribute `_markers` can be described in terms of a recursive type:
|
| 351 |
+
# MarkerList = List[Union[Tuple[Node, ...], str, MarkerList]]
|
| 352 |
+
#
|
| 353 |
+
# For example, the following expression:
|
| 354 |
+
# python_version > "3.6" or (python_version == "3.6" and os_name == "unix")
|
| 355 |
+
#
|
| 356 |
+
# is parsed into:
|
| 357 |
+
# [
|
| 358 |
+
# (<Variable('python_version')>, <Op('>')>, <Value('3.6')>),
|
| 359 |
+
# 'and',
|
| 360 |
+
# [
|
| 361 |
+
# (<Variable('python_version')>, <Op('==')>, <Value('3.6')>),
|
| 362 |
+
# 'or',
|
| 363 |
+
# (<Variable('os_name')>, <Op('==')>, <Value('unix')>)
|
| 364 |
+
# ]
|
| 365 |
+
# ]
|
| 366 |
+
except ParserSyntaxError as e:
|
| 367 |
+
raise InvalidMarker(str(e)) from e
|
| 368 |
+
|
| 369 |
+
@classmethod
|
| 370 |
+
def _from_markers(cls, markers: MarkerList) -> Marker:
|
| 371 |
+
"""Create a Marker instance from a pre-parsed marker tree.
|
| 372 |
+
|
| 373 |
+
This avoids re-parsing serialised marker strings when combining markers.
|
| 374 |
+
"""
|
| 375 |
+
new = cls.__new__(cls)
|
| 376 |
+
new._markers = markers
|
| 377 |
+
return new
|
| 378 |
+
|
| 379 |
+
def __str__(self) -> str:
|
| 380 |
+
return _format_marker(self._markers)
|
| 381 |
+
|
| 382 |
+
def __repr__(self) -> str:
|
| 383 |
+
return f"<{self.__class__.__name__}({str(self)!r})>"
|
| 384 |
+
|
| 385 |
+
def __hash__(self) -> int:
|
| 386 |
+
return hash(str(self))
|
| 387 |
+
|
| 388 |
+
def __eq__(self, other: object) -> bool:
|
| 389 |
+
if not isinstance(other, Marker):
|
| 390 |
+
return NotImplemented
|
| 391 |
+
|
| 392 |
+
return str(self) == str(other)
|
| 393 |
+
|
| 394 |
+
def __getstate__(self) -> str:
|
| 395 |
+
# Return the marker expression string for compactness and stability.
|
| 396 |
+
# Internal Node objects are excluded; the string is re-parsed on load.
|
| 397 |
+
return str(self)
|
| 398 |
+
|
| 399 |
+
def __setstate__(self, state: object) -> None:
|
| 400 |
+
if isinstance(state, str):
|
| 401 |
+
# New format (26.2+): just the marker expression string.
|
| 402 |
+
try:
|
| 403 |
+
self._markers = _normalize_extra_values(_parse_marker(state))
|
| 404 |
+
except ParserSyntaxError as exc:
|
| 405 |
+
raise TypeError(f"Cannot restore Marker from {state!r}") from exc
|
| 406 |
+
return
|
| 407 |
+
if isinstance(state, dict) and "_markers" in state:
|
| 408 |
+
# Old format (packaging <= 26.1, no __slots__): plain __dict__.
|
| 409 |
+
markers = state["_markers"]
|
| 410 |
+
if isinstance(markers, list):
|
| 411 |
+
self._markers = markers
|
| 412 |
+
return
|
| 413 |
+
if isinstance(state, tuple) and len(state) == 2:
|
| 414 |
+
# Old format (packaging <= 26.1, __slots__): (None, {slot: value}).
|
| 415 |
+
_, slot_dict = state
|
| 416 |
+
if isinstance(slot_dict, dict) and "_markers" in slot_dict:
|
| 417 |
+
markers = slot_dict["_markers"]
|
| 418 |
+
if isinstance(markers, list):
|
| 419 |
+
self._markers = markers
|
| 420 |
+
return
|
| 421 |
+
raise TypeError(f"Cannot restore Marker from {state!r}")
|
| 422 |
+
|
| 423 |
+
def __and__(self, other: Marker) -> Marker:
|
| 424 |
+
if not isinstance(other, Marker):
|
| 425 |
+
return NotImplemented
|
| 426 |
+
return self._from_markers([self._markers, "and", other._markers])
|
| 427 |
+
|
| 428 |
+
def __or__(self, other: Marker) -> Marker:
|
| 429 |
+
if not isinstance(other, Marker):
|
| 430 |
+
return NotImplemented
|
| 431 |
+
return self._from_markers([self._markers, "or", other._markers])
|
| 432 |
+
|
| 433 |
+
def evaluate(
|
| 434 |
+
self,
|
| 435 |
+
environment: Mapping[str, str | AbstractSet[str]] | None = None,
|
| 436 |
+
context: EvaluateContext = "metadata",
|
| 437 |
+
) -> bool:
|
| 438 |
+
"""Evaluate a marker.
|
| 439 |
+
|
| 440 |
+
Return the boolean from evaluating this marker against the environment.
|
| 441 |
+
The environment is determined from the current Python process unless
|
| 442 |
+
passed in explicitly.
|
| 443 |
+
|
| 444 |
+
:param environment: Mapping containing keys and values to override the
|
| 445 |
+
detected environment.
|
| 446 |
+
:param EvaluateContext context: The context in which the marker is
|
| 447 |
+
evaluated, which influences what marker names are considered valid.
|
| 448 |
+
Accepted values are ``"metadata"`` (for core metadata; default),
|
| 449 |
+
``"lock_file"``, and ``"requirement"`` (i.e. all other situations).
|
| 450 |
+
:raises UndefinedComparison: If the marker uses a comparison on values
|
| 451 |
+
that are not valid versions per the :ref:`specification of version
|
| 452 |
+
specifiers <pypug:version-specifiers>`.
|
| 453 |
+
:raises UndefinedEnvironmentName: If the marker references a value that
|
| 454 |
+
is missing from the evaluation environment.
|
| 455 |
+
:returns: ``True`` if the marker matches, otherwise ``False``.
|
| 456 |
+
|
| 457 |
+
"""
|
| 458 |
+
current_environment = cast(
|
| 459 |
+
"dict[str, str | AbstractSet[str]]", default_environment()
|
| 460 |
+
)
|
| 461 |
+
if context == "lock_file":
|
| 462 |
+
current_environment.update(
|
| 463 |
+
extras=frozenset(), dependency_groups=frozenset()
|
| 464 |
+
)
|
| 465 |
+
elif context == "metadata":
|
| 466 |
+
current_environment["extra"] = ""
|
| 467 |
+
|
| 468 |
+
if environment is not None:
|
| 469 |
+
current_environment.update(environment)
|
| 470 |
+
if "extra" in current_environment:
|
| 471 |
+
# The API used to allow setting extra to None. We need to handle
|
| 472 |
+
# this case for backwards compatibility. Also skip running
|
| 473 |
+
# normalize name if extra is empty.
|
| 474 |
+
extra = cast("str | None", current_environment["extra"])
|
| 475 |
+
current_environment["extra"] = canonicalize_name(extra) if extra else ""
|
| 476 |
+
|
| 477 |
+
return _evaluate_markers(
|
| 478 |
+
self._markers, _repair_python_full_version(current_environment)
|
| 479 |
+
)
|
| 480 |
+
|
| 481 |
+
|
| 482 |
+
def _repair_python_full_version(
|
| 483 |
+
env: dict[str, str | AbstractSet[str]],
|
| 484 |
+
) -> dict[str, str | AbstractSet[str]]:
|
| 485 |
+
"""
|
| 486 |
+
Work around platform.python_version() returning something that is not PEP 440
|
| 487 |
+
compliant for non-tagged Python builds.
|
| 488 |
+
"""
|
| 489 |
+
python_full_version = cast("str", env["python_full_version"])
|
| 490 |
+
if python_full_version.endswith("+"):
|
| 491 |
+
env["python_full_version"] = f"{python_full_version}local"
|
| 492 |
+
return env
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/metadata.py
ADDED
|
@@ -0,0 +1,964 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import email.header
|
| 4 |
+
import email.message
|
| 5 |
+
import email.parser
|
| 6 |
+
import email.policy
|
| 7 |
+
import keyword
|
| 8 |
+
import pathlib
|
| 9 |
+
import typing
|
| 10 |
+
from typing import (
|
| 11 |
+
Any,
|
| 12 |
+
Callable,
|
| 13 |
+
Generic,
|
| 14 |
+
Literal,
|
| 15 |
+
TypedDict,
|
| 16 |
+
cast,
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
from . import licenses, requirements, specifiers, utils
|
| 20 |
+
from . import version as version_module
|
| 21 |
+
from .errors import ExceptionGroup, _ErrorCollector
|
| 22 |
+
|
| 23 |
+
if typing.TYPE_CHECKING:
|
| 24 |
+
from .licenses import NormalizedLicenseExpression
|
| 25 |
+
|
| 26 |
+
T = typing.TypeVar("T")
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
__all__ = [
|
| 30 |
+
"ExceptionGroup", # Keep this for a bit (makes mypy happy w/ 26.0 compat)
|
| 31 |
+
"InvalidMetadata",
|
| 32 |
+
"Metadata",
|
| 33 |
+
"RFC822Message",
|
| 34 |
+
"RFC822Policy",
|
| 35 |
+
"RawMetadata",
|
| 36 |
+
"parse_email",
|
| 37 |
+
]
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def __dir__() -> list[str]:
|
| 41 |
+
return __all__
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
class InvalidMetadata(ValueError):
|
| 45 |
+
"""A metadata field contains invalid data."""
|
| 46 |
+
|
| 47 |
+
field: str
|
| 48 |
+
"""The name of the field that contains invalid data."""
|
| 49 |
+
|
| 50 |
+
def __init__(self, field: str, message: str) -> None:
|
| 51 |
+
self.field = field
|
| 52 |
+
super().__init__(message)
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
# The RawMetadata class attempts to make as few assumptions about the underlying
|
| 56 |
+
# serialization formats as possible. The idea is that as long as a serialization
|
| 57 |
+
# formats offer some very basic primitives in *some* way then we can support
|
| 58 |
+
# serializing to and from that format.
|
| 59 |
+
class RawMetadata(TypedDict, total=False):
|
| 60 |
+
"""A dictionary of raw core metadata.
|
| 61 |
+
|
| 62 |
+
Each field in core metadata maps to a key of this dictionary (when data is
|
| 63 |
+
provided). The key is lower-case and underscores are used instead of dashes
|
| 64 |
+
compared to the equivalent core metadata field. Any core metadata field that
|
| 65 |
+
can be specified multiple times or can hold multiple values in a single
|
| 66 |
+
field have a key with a plural name. See :class:`Metadata` whose attributes
|
| 67 |
+
match the keys of this dictionary.
|
| 68 |
+
|
| 69 |
+
Core metadata fields that can be specified multiple times are stored as a
|
| 70 |
+
list or dict depending on which is appropriate for the field. Any fields
|
| 71 |
+
which hold multiple values in a single field are stored as a list. All fields
|
| 72 |
+
are considered optional.
|
| 73 |
+
"""
|
| 74 |
+
|
| 75 |
+
# Metadata 1.0 - PEP 241
|
| 76 |
+
metadata_version: str
|
| 77 |
+
name: str
|
| 78 |
+
version: str
|
| 79 |
+
platforms: list[str]
|
| 80 |
+
summary: str
|
| 81 |
+
description: str
|
| 82 |
+
keywords: list[str]
|
| 83 |
+
home_page: str
|
| 84 |
+
author: str
|
| 85 |
+
author_email: str
|
| 86 |
+
license: str
|
| 87 |
+
|
| 88 |
+
# Metadata 1.1 - PEP 314
|
| 89 |
+
supported_platforms: list[str]
|
| 90 |
+
download_url: str
|
| 91 |
+
classifiers: list[str]
|
| 92 |
+
requires: list[str]
|
| 93 |
+
provides: list[str]
|
| 94 |
+
obsoletes: list[str]
|
| 95 |
+
|
| 96 |
+
# Metadata 1.2 - PEP 345
|
| 97 |
+
maintainer: str
|
| 98 |
+
maintainer_email: str
|
| 99 |
+
requires_dist: list[str]
|
| 100 |
+
provides_dist: list[str]
|
| 101 |
+
obsoletes_dist: list[str]
|
| 102 |
+
requires_python: str
|
| 103 |
+
requires_external: list[str]
|
| 104 |
+
project_urls: dict[str, str]
|
| 105 |
+
|
| 106 |
+
# Metadata 2.0
|
| 107 |
+
# PEP 426 attempted to completely revamp the metadata format
|
| 108 |
+
# but got stuck without ever being able to build consensus on
|
| 109 |
+
# it and ultimately ended up withdrawn.
|
| 110 |
+
#
|
| 111 |
+
# However, a number of tools had started emitting METADATA with
|
| 112 |
+
# `2.0` Metadata-Version, so for historical reasons, this version
|
| 113 |
+
# was skipped.
|
| 114 |
+
|
| 115 |
+
# Metadata 2.1 - PEP 566
|
| 116 |
+
description_content_type: str
|
| 117 |
+
provides_extra: list[str]
|
| 118 |
+
|
| 119 |
+
# Metadata 2.2 - PEP 643
|
| 120 |
+
dynamic: list[str]
|
| 121 |
+
|
| 122 |
+
# Metadata 2.3 - PEP 685
|
| 123 |
+
# No new fields were added in PEP 685, just some edge case were
|
| 124 |
+
# tightened up to provide better interoperability.
|
| 125 |
+
|
| 126 |
+
# Metadata 2.4 - PEP 639
|
| 127 |
+
license_expression: str
|
| 128 |
+
license_files: list[str]
|
| 129 |
+
|
| 130 |
+
# Metadata 2.5 - PEP 794
|
| 131 |
+
import_names: list[str]
|
| 132 |
+
import_namespaces: list[str]
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
# 'keywords' is special as it's a string in the core metadata spec, but we
|
| 136 |
+
# represent it as a list.
|
| 137 |
+
_STRING_FIELDS = {
|
| 138 |
+
"author",
|
| 139 |
+
"author_email",
|
| 140 |
+
"description",
|
| 141 |
+
"description_content_type",
|
| 142 |
+
"download_url",
|
| 143 |
+
"home_page",
|
| 144 |
+
"license",
|
| 145 |
+
"license_expression",
|
| 146 |
+
"maintainer",
|
| 147 |
+
"maintainer_email",
|
| 148 |
+
"metadata_version",
|
| 149 |
+
"name",
|
| 150 |
+
"requires_python",
|
| 151 |
+
"summary",
|
| 152 |
+
"version",
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
_LIST_FIELDS = {
|
| 156 |
+
"classifiers",
|
| 157 |
+
"dynamic",
|
| 158 |
+
"license_files",
|
| 159 |
+
"obsoletes",
|
| 160 |
+
"obsoletes_dist",
|
| 161 |
+
"platforms",
|
| 162 |
+
"provides",
|
| 163 |
+
"provides_dist",
|
| 164 |
+
"provides_extra",
|
| 165 |
+
"requires",
|
| 166 |
+
"requires_dist",
|
| 167 |
+
"requires_external",
|
| 168 |
+
"supported_platforms",
|
| 169 |
+
"import_names",
|
| 170 |
+
"import_namespaces",
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
_DICT_FIELDS = {
|
| 174 |
+
"project_urls",
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def _parse_keywords(data: str) -> list[str]:
|
| 179 |
+
"""Split a string of comma-separated keywords into a list of keywords."""
|
| 180 |
+
return [k.strip() for k in data.split(",")]
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
def _parse_project_urls(data: list[str]) -> dict[str, str]:
|
| 184 |
+
"""Parse a list of label/URL string pairings separated by a comma."""
|
| 185 |
+
urls = {}
|
| 186 |
+
for pair in data:
|
| 187 |
+
# Our logic is slightly tricky here as we want to try and do
|
| 188 |
+
# *something* reasonable with malformed data.
|
| 189 |
+
#
|
| 190 |
+
# The main thing that we have to worry about, is data that does
|
| 191 |
+
# not have a ',' at all to split the label from the Value. There
|
| 192 |
+
# isn't a singular right answer here, and we will fail validation
|
| 193 |
+
# later on (if the caller is validating) so it doesn't *really*
|
| 194 |
+
# matter, but since the missing value has to be an empty str
|
| 195 |
+
# and our return value is dict[str, str], if we let the key
|
| 196 |
+
# be the missing value, then they'd have multiple '' values that
|
| 197 |
+
# overwrite each other in a accumulating dict.
|
| 198 |
+
#
|
| 199 |
+
# The other potential issue is that it's possible to have the
|
| 200 |
+
# same label multiple times in the metadata, with no solid "right"
|
| 201 |
+
# answer with what to do in that case. As such, we'll do the only
|
| 202 |
+
# thing we can, which is treat the field as unparsable and add it
|
| 203 |
+
# to our list of unparsed fields.
|
| 204 |
+
#
|
| 205 |
+
# TODO: The spec doesn't say anything about if the keys should be
|
| 206 |
+
# considered case sensitive or not... logically they should
|
| 207 |
+
# be case-preserving and case-insensitive, but doing that
|
| 208 |
+
# would open up more cases where we might have duplicate
|
| 209 |
+
# entries.
|
| 210 |
+
label, _, url = (s.strip() for s in pair.partition(","))
|
| 211 |
+
|
| 212 |
+
if label in urls:
|
| 213 |
+
# The label already exists in our set of urls, so this field
|
| 214 |
+
# is unparsable, and we can just add the whole thing to our
|
| 215 |
+
# unparsable data and stop processing it.
|
| 216 |
+
raise KeyError("duplicate labels in project urls")
|
| 217 |
+
urls[label] = url
|
| 218 |
+
|
| 219 |
+
return urls
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
def _get_payload(msg: email.message.Message, source: bytes | str) -> str:
|
| 223 |
+
"""Get the body of the message."""
|
| 224 |
+
# If our source is a str, then our caller has managed encodings for us,
|
| 225 |
+
# and we don't need to deal with it.
|
| 226 |
+
if isinstance(source, str):
|
| 227 |
+
payload = msg.get_payload()
|
| 228 |
+
assert isinstance(payload, str)
|
| 229 |
+
return payload
|
| 230 |
+
# If our source is a bytes, then we're managing the encoding and we need
|
| 231 |
+
# to deal with it.
|
| 232 |
+
else:
|
| 233 |
+
bpayload = msg.get_payload(decode=True)
|
| 234 |
+
assert isinstance(bpayload, bytes)
|
| 235 |
+
try:
|
| 236 |
+
return bpayload.decode("utf8", "strict")
|
| 237 |
+
except UnicodeDecodeError as exc:
|
| 238 |
+
raise ValueError("payload in an invalid encoding") from exc
|
| 239 |
+
|
| 240 |
+
|
| 241 |
+
# The various parse_FORMAT functions here are intended to be as lenient as
|
| 242 |
+
# possible in their parsing, while still returning a correctly typed
|
| 243 |
+
# RawMetadata.
|
| 244 |
+
#
|
| 245 |
+
# To aid in this, we also generally want to do as little touching of the
|
| 246 |
+
# data as possible, except where there are possibly some historic holdovers
|
| 247 |
+
# that make valid data awkward to work with.
|
| 248 |
+
#
|
| 249 |
+
# While this is a lower level, intermediate format than our ``Metadata``
|
| 250 |
+
# class, some light touch ups can make a massive difference in usability.
|
| 251 |
+
|
| 252 |
+
# Map METADATA fields to RawMetadata.
|
| 253 |
+
_EMAIL_TO_RAW_MAPPING = {
|
| 254 |
+
"author": "author",
|
| 255 |
+
"author-email": "author_email",
|
| 256 |
+
"classifier": "classifiers",
|
| 257 |
+
"description": "description",
|
| 258 |
+
"description-content-type": "description_content_type",
|
| 259 |
+
"download-url": "download_url",
|
| 260 |
+
"dynamic": "dynamic",
|
| 261 |
+
"home-page": "home_page",
|
| 262 |
+
"import-name": "import_names",
|
| 263 |
+
"import-namespace": "import_namespaces",
|
| 264 |
+
"keywords": "keywords",
|
| 265 |
+
"license": "license",
|
| 266 |
+
"license-expression": "license_expression",
|
| 267 |
+
"license-file": "license_files",
|
| 268 |
+
"maintainer": "maintainer",
|
| 269 |
+
"maintainer-email": "maintainer_email",
|
| 270 |
+
"metadata-version": "metadata_version",
|
| 271 |
+
"name": "name",
|
| 272 |
+
"obsoletes": "obsoletes",
|
| 273 |
+
"obsoletes-dist": "obsoletes_dist",
|
| 274 |
+
"platform": "platforms",
|
| 275 |
+
"project-url": "project_urls",
|
| 276 |
+
"provides": "provides",
|
| 277 |
+
"provides-dist": "provides_dist",
|
| 278 |
+
"provides-extra": "provides_extra",
|
| 279 |
+
"requires": "requires",
|
| 280 |
+
"requires-dist": "requires_dist",
|
| 281 |
+
"requires-external": "requires_external",
|
| 282 |
+
"requires-python": "requires_python",
|
| 283 |
+
"summary": "summary",
|
| 284 |
+
"supported-platform": "supported_platforms",
|
| 285 |
+
"version": "version",
|
| 286 |
+
}
|
| 287 |
+
_RAW_TO_EMAIL_MAPPING = {raw: email for email, raw in _EMAIL_TO_RAW_MAPPING.items()}
|
| 288 |
+
|
| 289 |
+
|
| 290 |
+
# This class is for writing RFC822 messages
|
| 291 |
+
class RFC822Policy(email.policy.EmailPolicy):
|
| 292 |
+
"""
|
| 293 |
+
This is :class:`email.policy.EmailPolicy`, but with a simple ``header_store_parse``
|
| 294 |
+
implementation that handles multi-line values, and some nice defaults.
|
| 295 |
+
"""
|
| 296 |
+
|
| 297 |
+
utf8 = True
|
| 298 |
+
mangle_from_ = False
|
| 299 |
+
max_line_length = 0
|
| 300 |
+
|
| 301 |
+
def header_store_parse(self, name: str, value: str) -> tuple[str, str]:
|
| 302 |
+
size = len(name) + 2
|
| 303 |
+
value = value.replace("\n", "\n" + " " * size)
|
| 304 |
+
return (name, value)
|
| 305 |
+
|
| 306 |
+
|
| 307 |
+
# This class is for writing RFC822 messages
|
| 308 |
+
class RFC822Message(email.message.EmailMessage):
|
| 309 |
+
"""
|
| 310 |
+
This is :class:`email.message.EmailMessage` with two small changes: it defaults to
|
| 311 |
+
our `RFC822Policy`, and it correctly writes unicode when being called
|
| 312 |
+
with `bytes()`.
|
| 313 |
+
"""
|
| 314 |
+
|
| 315 |
+
def __init__(self) -> None:
|
| 316 |
+
super().__init__(policy=RFC822Policy())
|
| 317 |
+
|
| 318 |
+
def as_bytes(
|
| 319 |
+
self, unixfrom: bool = False, policy: email.policy.Policy | None = None
|
| 320 |
+
) -> bytes:
|
| 321 |
+
"""
|
| 322 |
+
Return the bytes representation of the message.
|
| 323 |
+
|
| 324 |
+
This handles unicode encoding.
|
| 325 |
+
"""
|
| 326 |
+
return self.as_string(unixfrom, policy=policy).encode("utf-8")
|
| 327 |
+
|
| 328 |
+
|
| 329 |
+
def parse_email(data: bytes | str) -> tuple[RawMetadata, dict[str, list[str]]]:
|
| 330 |
+
"""Parse a distribution's metadata stored as email headers (e.g. from ``METADATA``).
|
| 331 |
+
|
| 332 |
+
This function returns a two-item tuple of dicts. The first dict is of
|
| 333 |
+
recognized fields from the core metadata specification. Fields that can be
|
| 334 |
+
parsed and translated into Python's built-in types are converted
|
| 335 |
+
appropriately. All other fields are left as-is. Fields that are allowed to
|
| 336 |
+
appear multiple times are stored as lists.
|
| 337 |
+
|
| 338 |
+
The second dict contains all other fields from the metadata. This includes
|
| 339 |
+
any unrecognized fields. It also includes any fields which are expected to
|
| 340 |
+
be parsed into a built-in type but were not formatted appropriately. Finally,
|
| 341 |
+
any fields that are expected to appear only once but are repeated are
|
| 342 |
+
included in this dict.
|
| 343 |
+
|
| 344 |
+
"""
|
| 345 |
+
raw: dict[str, str | list[str] | dict[str, str]] = {}
|
| 346 |
+
unparsed: dict[str, list[str]] = {}
|
| 347 |
+
|
| 348 |
+
if isinstance(data, str):
|
| 349 |
+
parsed = email.parser.Parser(policy=email.policy.compat32).parsestr(data)
|
| 350 |
+
else:
|
| 351 |
+
parsed = email.parser.BytesParser(policy=email.policy.compat32).parsebytes(data)
|
| 352 |
+
|
| 353 |
+
# We have to wrap parsed.keys() in a set, because in the case of multiple
|
| 354 |
+
# values for a key (a list), the key will appear multiple times in the
|
| 355 |
+
# list of keys, but we're avoiding that by using get_all().
|
| 356 |
+
for name_with_case in frozenset(parsed.keys()):
|
| 357 |
+
# Header names in RFC are case insensitive, so we'll normalize to all
|
| 358 |
+
# lower case to make comparisons easier.
|
| 359 |
+
name = name_with_case.lower()
|
| 360 |
+
|
| 361 |
+
# We use get_all() here, even for fields that aren't multiple use,
|
| 362 |
+
# because otherwise someone could have e.g. two Name fields, and we
|
| 363 |
+
# would just silently ignore it rather than doing something about it.
|
| 364 |
+
headers = parsed.get_all(name) or []
|
| 365 |
+
|
| 366 |
+
# The way the email module works when parsing bytes is that it
|
| 367 |
+
# unconditionally decodes the bytes as ascii using the surrogateescape
|
| 368 |
+
# handler. When you pull that data back out (such as with get_all() ),
|
| 369 |
+
# it looks to see if the str has any surrogate escapes, and if it does
|
| 370 |
+
# it wraps it in a Header object instead of returning the string.
|
| 371 |
+
#
|
| 372 |
+
# As such, we'll look for those Header objects, and fix up the encoding.
|
| 373 |
+
value = []
|
| 374 |
+
# Flag if we have run into any issues processing the headers, thus
|
| 375 |
+
# signalling that the data belongs in 'unparsed'.
|
| 376 |
+
valid_encoding = True
|
| 377 |
+
for h in headers:
|
| 378 |
+
# It's unclear if this can return more types than just a Header or
|
| 379 |
+
# a str, so we'll just assert here to make sure.
|
| 380 |
+
assert isinstance(h, (email.header.Header, str))
|
| 381 |
+
|
| 382 |
+
# If it's a header object, we need to do our little dance to get
|
| 383 |
+
# the real data out of it. In cases where there is invalid data
|
| 384 |
+
# we're going to end up with mojibake, but there's no obvious, good
|
| 385 |
+
# way around that without reimplementing parts of the Header object
|
| 386 |
+
# ourselves.
|
| 387 |
+
#
|
| 388 |
+
# That should be fine since, if mojibacked happens, this key is
|
| 389 |
+
# going into the unparsed dict anyways.
|
| 390 |
+
if isinstance(h, email.header.Header):
|
| 391 |
+
# The Header object stores it's data as chunks, and each chunk
|
| 392 |
+
# can be independently encoded, so we'll need to check each
|
| 393 |
+
# of them.
|
| 394 |
+
chunks: list[tuple[bytes, str | None]] = []
|
| 395 |
+
for binary, _encoding in email.header.decode_header(h):
|
| 396 |
+
try:
|
| 397 |
+
binary.decode("utf8", "strict")
|
| 398 |
+
except UnicodeDecodeError:
|
| 399 |
+
# Enable mojibake.
|
| 400 |
+
encoding = "latin1"
|
| 401 |
+
valid_encoding = False
|
| 402 |
+
else:
|
| 403 |
+
encoding = "utf8"
|
| 404 |
+
chunks.append((binary, encoding))
|
| 405 |
+
|
| 406 |
+
# Turn our chunks back into a Header object, then let that
|
| 407 |
+
# Header object do the right thing to turn them into a
|
| 408 |
+
# string for us.
|
| 409 |
+
value.append(str(email.header.make_header(chunks)))
|
| 410 |
+
# This is already a string, so just add it.
|
| 411 |
+
else:
|
| 412 |
+
value.append(h)
|
| 413 |
+
|
| 414 |
+
# We've processed all of our values to get them into a list of str,
|
| 415 |
+
# but we may have mojibake data, in which case this is an unparsed
|
| 416 |
+
# field.
|
| 417 |
+
if not valid_encoding:
|
| 418 |
+
unparsed[name] = value
|
| 419 |
+
continue
|
| 420 |
+
|
| 421 |
+
raw_name = _EMAIL_TO_RAW_MAPPING.get(name)
|
| 422 |
+
if raw_name is None:
|
| 423 |
+
# This is a bit of a weird situation, we've encountered a key that
|
| 424 |
+
# we don't know what it means, so we don't know whether it's meant
|
| 425 |
+
# to be a list or not.
|
| 426 |
+
#
|
| 427 |
+
# Since we can't really tell one way or another, we'll just leave it
|
| 428 |
+
# as a list, even though it may be a single item list, because that's
|
| 429 |
+
# what makes the most sense for email headers.
|
| 430 |
+
unparsed[name] = value
|
| 431 |
+
continue
|
| 432 |
+
|
| 433 |
+
# If this is one of our string fields, then we'll check to see if our
|
| 434 |
+
# value is a list of a single item. If it is then we'll assume that
|
| 435 |
+
# it was emitted as a single string, and unwrap the str from inside
|
| 436 |
+
# the list.
|
| 437 |
+
#
|
| 438 |
+
# If it's any other kind of data, then we haven't the faintest clue
|
| 439 |
+
# what we should parse it as, and we have to just add it to our list
|
| 440 |
+
# of unparsed stuff.
|
| 441 |
+
if raw_name in _STRING_FIELDS and len(value) == 1:
|
| 442 |
+
raw[raw_name] = value[0]
|
| 443 |
+
# If this is import_names, we need to special case the empty field
|
| 444 |
+
# case, which converts to an empty list instead of None. We can't let
|
| 445 |
+
# the empty case slip through, as it will fail validation.
|
| 446 |
+
elif raw_name == "import_names" and value == [""]:
|
| 447 |
+
raw[raw_name] = []
|
| 448 |
+
# If this is one of our list of string fields, then we can just assign
|
| 449 |
+
# the value, since email *only* has strings, and our get_all() call
|
| 450 |
+
# above ensures that this is a list.
|
| 451 |
+
elif raw_name in _LIST_FIELDS:
|
| 452 |
+
raw[raw_name] = value
|
| 453 |
+
# Special Case: Keywords
|
| 454 |
+
# The keywords field is implemented in the metadata spec as a str,
|
| 455 |
+
# but it conceptually is a list of strings, and is serialized using
|
| 456 |
+
# ", ".join(keywords), so we'll do some light data massaging to turn
|
| 457 |
+
# this into what it logically is.
|
| 458 |
+
elif raw_name == "keywords" and len(value) == 1:
|
| 459 |
+
raw[raw_name] = _parse_keywords(value[0])
|
| 460 |
+
# Special Case: Project-URL
|
| 461 |
+
# The project urls is implemented in the metadata spec as a list of
|
| 462 |
+
# specially-formatted strings that represent a key and a value, which
|
| 463 |
+
# is fundamentally a mapping, however the email format doesn't support
|
| 464 |
+
# mappings in a sane way, so it was crammed into a list of strings
|
| 465 |
+
# instead.
|
| 466 |
+
#
|
| 467 |
+
# We will do a little light data massaging to turn this into a map as
|
| 468 |
+
# it logically should be.
|
| 469 |
+
elif raw_name == "project_urls":
|
| 470 |
+
try:
|
| 471 |
+
raw[raw_name] = _parse_project_urls(value)
|
| 472 |
+
except KeyError:
|
| 473 |
+
unparsed[name] = value
|
| 474 |
+
# Nothing that we've done has managed to parse this, so it'll just
|
| 475 |
+
# throw it in our unparsable data and move on.
|
| 476 |
+
else:
|
| 477 |
+
unparsed[name] = value
|
| 478 |
+
|
| 479 |
+
# We need to support getting the Description from the message payload in
|
| 480 |
+
# addition to getting it from the the headers. This does mean, though, there
|
| 481 |
+
# is the possibility of it being set both ways, in which case we put both
|
| 482 |
+
# in 'unparsed' since we don't know which is right.
|
| 483 |
+
try:
|
| 484 |
+
payload = _get_payload(parsed, data)
|
| 485 |
+
except ValueError:
|
| 486 |
+
unparsed.setdefault("description", []).append(
|
| 487 |
+
parsed.get_payload(decode=isinstance(data, bytes)) # type: ignore[call-overload]
|
| 488 |
+
)
|
| 489 |
+
else:
|
| 490 |
+
if payload:
|
| 491 |
+
# Check to see if we've already got a description, if so then both
|
| 492 |
+
# it, and this body move to unparsable.
|
| 493 |
+
if "description" in raw:
|
| 494 |
+
description_header = cast("str", raw.pop("description"))
|
| 495 |
+
unparsed.setdefault("description", []).extend(
|
| 496 |
+
[description_header, payload]
|
| 497 |
+
)
|
| 498 |
+
elif "description" in unparsed:
|
| 499 |
+
unparsed["description"].append(payload)
|
| 500 |
+
else:
|
| 501 |
+
raw["description"] = payload
|
| 502 |
+
|
| 503 |
+
# We need to cast our `raw` to a metadata, because a TypedDict only support
|
| 504 |
+
# literal key names, but we're computing our key names on purpose, but the
|
| 505 |
+
# way this function is implemented, our `TypedDict` can only have valid key
|
| 506 |
+
# names.
|
| 507 |
+
return cast("RawMetadata", raw), unparsed
|
| 508 |
+
|
| 509 |
+
|
| 510 |
+
_NOT_FOUND = object()
|
| 511 |
+
|
| 512 |
+
|
| 513 |
+
# Keep the two values in sync.
|
| 514 |
+
_VALID_METADATA_VERSIONS = ["1.0", "1.1", "1.2", "2.1", "2.2", "2.3", "2.4", "2.5"]
|
| 515 |
+
_MetadataVersion = Literal["1.0", "1.1", "1.2", "2.1", "2.2", "2.3", "2.4", "2.5"]
|
| 516 |
+
|
| 517 |
+
_REQUIRED_ATTRS = frozenset(["metadata_version", "name", "version"])
|
| 518 |
+
|
| 519 |
+
|
| 520 |
+
class _Validator(Generic[T]):
|
| 521 |
+
"""Validate a metadata field.
|
| 522 |
+
|
| 523 |
+
All _process_*() methods correspond to a core metadata field. The method is
|
| 524 |
+
called with the field's raw value. If the raw value is valid it is returned
|
| 525 |
+
in its "enriched" form (e.g. ``version.Version`` for the ``Version`` field).
|
| 526 |
+
If the raw value is invalid, :exc:`InvalidMetadata` is raised (with a cause
|
| 527 |
+
as appropriate).
|
| 528 |
+
"""
|
| 529 |
+
|
| 530 |
+
name: str
|
| 531 |
+
raw_name: str
|
| 532 |
+
added: _MetadataVersion
|
| 533 |
+
|
| 534 |
+
def __init__(
|
| 535 |
+
self,
|
| 536 |
+
*,
|
| 537 |
+
added: _MetadataVersion = "1.0",
|
| 538 |
+
) -> None:
|
| 539 |
+
self.added = added
|
| 540 |
+
|
| 541 |
+
def __set_name__(self, _owner: Metadata, name: str) -> None:
|
| 542 |
+
self.name = name
|
| 543 |
+
self.raw_name = _RAW_TO_EMAIL_MAPPING[name]
|
| 544 |
+
|
| 545 |
+
def __get__(self, instance: Metadata, _owner: type[Metadata]) -> T:
|
| 546 |
+
# With Python 3.8, the caching can be replaced with functools.cached_property().
|
| 547 |
+
# No need to check the cache as attribute lookup will resolve into the
|
| 548 |
+
# instance's __dict__ before __get__ is called.
|
| 549 |
+
cache = instance.__dict__
|
| 550 |
+
value = instance._raw.get(self.name)
|
| 551 |
+
|
| 552 |
+
# To make the _process_* methods easier, we'll check if the value is None
|
| 553 |
+
# and if this field is NOT a required attribute, and if both of those
|
| 554 |
+
# things are true, we'll skip the the converter. This will mean that the
|
| 555 |
+
# converters never have to deal with the None union.
|
| 556 |
+
if self.name in _REQUIRED_ATTRS or value is not None:
|
| 557 |
+
try:
|
| 558 |
+
converter: Callable[[Any], T] = getattr(self, f"_process_{self.name}")
|
| 559 |
+
except AttributeError:
|
| 560 |
+
pass
|
| 561 |
+
else:
|
| 562 |
+
value = converter(value)
|
| 563 |
+
|
| 564 |
+
cache[self.name] = value
|
| 565 |
+
try:
|
| 566 |
+
del instance._raw[self.name] # type: ignore[misc]
|
| 567 |
+
except KeyError:
|
| 568 |
+
pass
|
| 569 |
+
|
| 570 |
+
return cast("T", value)
|
| 571 |
+
|
| 572 |
+
def _invalid_metadata(
|
| 573 |
+
self, msg: str, cause: Exception | None = None
|
| 574 |
+
) -> InvalidMetadata:
|
| 575 |
+
exc = InvalidMetadata(
|
| 576 |
+
self.raw_name, msg.format_map({"field": repr(self.raw_name)})
|
| 577 |
+
)
|
| 578 |
+
exc.__cause__ = cause
|
| 579 |
+
return exc
|
| 580 |
+
|
| 581 |
+
def _process_metadata_version(self, value: str) -> _MetadataVersion:
|
| 582 |
+
# Implicitly makes Metadata-Version required.
|
| 583 |
+
if value not in _VALID_METADATA_VERSIONS:
|
| 584 |
+
raise self._invalid_metadata(f"{value!r} is not a valid metadata version")
|
| 585 |
+
return cast("_MetadataVersion", value)
|
| 586 |
+
|
| 587 |
+
def _process_name(self, value: str) -> str:
|
| 588 |
+
if not value:
|
| 589 |
+
raise self._invalid_metadata("{field} is a required field")
|
| 590 |
+
# Validate the name as a side-effect.
|
| 591 |
+
try:
|
| 592 |
+
utils.canonicalize_name(value, validate=True)
|
| 593 |
+
except utils.InvalidName as exc:
|
| 594 |
+
raise self._invalid_metadata(
|
| 595 |
+
f"{value!r} is invalid for {{field}}", cause=exc
|
| 596 |
+
) from exc
|
| 597 |
+
else:
|
| 598 |
+
return value
|
| 599 |
+
|
| 600 |
+
def _process_version(self, value: str) -> version_module.Version:
|
| 601 |
+
if not value:
|
| 602 |
+
raise self._invalid_metadata("{field} is a required field")
|
| 603 |
+
try:
|
| 604 |
+
return version_module.parse(value)
|
| 605 |
+
except version_module.InvalidVersion as exc:
|
| 606 |
+
raise self._invalid_metadata(
|
| 607 |
+
f"{value!r} is invalid for {{field}}", cause=exc
|
| 608 |
+
) from exc
|
| 609 |
+
|
| 610 |
+
def _process_summary(self, value: str) -> str:
|
| 611 |
+
"""Check the field contains no newlines."""
|
| 612 |
+
if "\n" in value:
|
| 613 |
+
raise self._invalid_metadata("{field} must be a single line")
|
| 614 |
+
return value
|
| 615 |
+
|
| 616 |
+
def _process_description_content_type(self, value: str) -> str:
|
| 617 |
+
content_types = {"text/plain", "text/x-rst", "text/markdown"}
|
| 618 |
+
message = email.message.EmailMessage()
|
| 619 |
+
message["content-type"] = value
|
| 620 |
+
|
| 621 |
+
content_type, parameters = (
|
| 622 |
+
# Defaults to `text/plain` if parsing failed.
|
| 623 |
+
message.get_content_type().lower(),
|
| 624 |
+
message["content-type"].params,
|
| 625 |
+
)
|
| 626 |
+
# Check if content-type is valid or defaulted to `text/plain` and thus was
|
| 627 |
+
# not parseable.
|
| 628 |
+
if content_type not in content_types or content_type not in value.lower():
|
| 629 |
+
raise self._invalid_metadata(
|
| 630 |
+
f"{{field}} must be one of {list(content_types)}, not {value!r}"
|
| 631 |
+
)
|
| 632 |
+
|
| 633 |
+
charset = parameters.get("charset", "UTF-8")
|
| 634 |
+
if charset != "UTF-8":
|
| 635 |
+
raise self._invalid_metadata(
|
| 636 |
+
f"{{field}} can only specify the UTF-8 charset, not {charset!r}"
|
| 637 |
+
)
|
| 638 |
+
|
| 639 |
+
markdown_variants = {"GFM", "CommonMark"}
|
| 640 |
+
variant = parameters.get("variant", "GFM") # Use an acceptable default.
|
| 641 |
+
if content_type == "text/markdown" and variant not in markdown_variants:
|
| 642 |
+
raise self._invalid_metadata(
|
| 643 |
+
f"valid Markdown variants for {{field}} are {list(markdown_variants)}, "
|
| 644 |
+
f"not {variant!r}",
|
| 645 |
+
)
|
| 646 |
+
return value
|
| 647 |
+
|
| 648 |
+
def _process_dynamic(self, value: list[str]) -> list[str]:
|
| 649 |
+
for dynamic_field in map(str.lower, value):
|
| 650 |
+
if dynamic_field in {"name", "version", "metadata-version"}:
|
| 651 |
+
raise self._invalid_metadata(
|
| 652 |
+
f"{dynamic_field!r} is not allowed as a dynamic field"
|
| 653 |
+
)
|
| 654 |
+
elif dynamic_field not in _EMAIL_TO_RAW_MAPPING:
|
| 655 |
+
raise self._invalid_metadata(
|
| 656 |
+
f"{dynamic_field!r} is not a valid dynamic field"
|
| 657 |
+
)
|
| 658 |
+
return list(map(str.lower, value))
|
| 659 |
+
|
| 660 |
+
def _process_provides_extra(
|
| 661 |
+
self,
|
| 662 |
+
value: list[str],
|
| 663 |
+
) -> list[utils.NormalizedName]:
|
| 664 |
+
normalized_names = []
|
| 665 |
+
try:
|
| 666 |
+
for name in value:
|
| 667 |
+
normalized_names.append(utils.canonicalize_name(name, validate=True))
|
| 668 |
+
except utils.InvalidName as exc:
|
| 669 |
+
raise self._invalid_metadata(
|
| 670 |
+
f"{name!r} is invalid for {{field}}", cause=exc
|
| 671 |
+
) from exc
|
| 672 |
+
else:
|
| 673 |
+
return normalized_names
|
| 674 |
+
|
| 675 |
+
def _process_requires_python(self, value: str) -> specifiers.SpecifierSet:
|
| 676 |
+
try:
|
| 677 |
+
return specifiers.SpecifierSet(value)
|
| 678 |
+
except specifiers.InvalidSpecifier as exc:
|
| 679 |
+
raise self._invalid_metadata(
|
| 680 |
+
f"{value!r} is invalid for {{field}}", cause=exc
|
| 681 |
+
) from exc
|
| 682 |
+
|
| 683 |
+
def _process_requires_dist(
|
| 684 |
+
self,
|
| 685 |
+
value: list[str],
|
| 686 |
+
) -> list[requirements.Requirement]:
|
| 687 |
+
reqs = []
|
| 688 |
+
try:
|
| 689 |
+
for req in value:
|
| 690 |
+
reqs.append(requirements.Requirement(req))
|
| 691 |
+
except requirements.InvalidRequirement as exc:
|
| 692 |
+
raise self._invalid_metadata(
|
| 693 |
+
f"{req!r} is invalid for {{field}}", cause=exc
|
| 694 |
+
) from exc
|
| 695 |
+
else:
|
| 696 |
+
return reqs
|
| 697 |
+
|
| 698 |
+
def _process_license_expression(self, value: str) -> NormalizedLicenseExpression:
|
| 699 |
+
try:
|
| 700 |
+
return licenses.canonicalize_license_expression(value)
|
| 701 |
+
except ValueError as exc:
|
| 702 |
+
raise self._invalid_metadata(
|
| 703 |
+
f"{value!r} is invalid for {{field}}", cause=exc
|
| 704 |
+
) from exc
|
| 705 |
+
|
| 706 |
+
def _process_license_files(self, value: list[str]) -> list[str]:
|
| 707 |
+
paths = []
|
| 708 |
+
for path in value:
|
| 709 |
+
if ".." in path:
|
| 710 |
+
raise self._invalid_metadata(
|
| 711 |
+
f"{path!r} is invalid for {{field}}, "
|
| 712 |
+
"parent directory indicators are not allowed"
|
| 713 |
+
)
|
| 714 |
+
if "*" in path:
|
| 715 |
+
raise self._invalid_metadata(
|
| 716 |
+
f"{path!r} is invalid for {{field}}, paths must be resolved"
|
| 717 |
+
)
|
| 718 |
+
if (
|
| 719 |
+
pathlib.PurePosixPath(path).is_absolute()
|
| 720 |
+
or pathlib.PureWindowsPath(path).is_absolute()
|
| 721 |
+
):
|
| 722 |
+
raise self._invalid_metadata(
|
| 723 |
+
f"{path!r} is invalid for {{field}}, paths must be relative"
|
| 724 |
+
)
|
| 725 |
+
if pathlib.PureWindowsPath(path).as_posix() != path:
|
| 726 |
+
raise self._invalid_metadata(
|
| 727 |
+
f"{path!r} is invalid for {{field}}, paths must use '/' delimiter"
|
| 728 |
+
)
|
| 729 |
+
paths.append(path)
|
| 730 |
+
return paths
|
| 731 |
+
|
| 732 |
+
def _process_import_names(self, value: list[str]) -> list[str]:
|
| 733 |
+
for import_name in value:
|
| 734 |
+
name, semicolon, private = import_name.partition(";")
|
| 735 |
+
name = name.rstrip()
|
| 736 |
+
for identifier in name.split("."):
|
| 737 |
+
if not identifier.isidentifier():
|
| 738 |
+
raise self._invalid_metadata(
|
| 739 |
+
f"{name!r} is invalid for {{field}}; "
|
| 740 |
+
f"{identifier!r} is not a valid identifier"
|
| 741 |
+
)
|
| 742 |
+
elif keyword.iskeyword(identifier):
|
| 743 |
+
raise self._invalid_metadata(
|
| 744 |
+
f"{name!r} is invalid for {{field}}; "
|
| 745 |
+
f"{identifier!r} is a keyword"
|
| 746 |
+
)
|
| 747 |
+
if semicolon and private.lstrip() != "private":
|
| 748 |
+
raise self._invalid_metadata(
|
| 749 |
+
f"{import_name!r} is invalid for {{field}}; "
|
| 750 |
+
"the only valid option is 'private'"
|
| 751 |
+
)
|
| 752 |
+
return value
|
| 753 |
+
|
| 754 |
+
_process_import_namespaces = _process_import_names
|
| 755 |
+
|
| 756 |
+
|
| 757 |
+
class Metadata:
|
| 758 |
+
"""Representation of distribution metadata.
|
| 759 |
+
|
| 760 |
+
Compared to :class:`RawMetadata`, this class provides objects representing
|
| 761 |
+
metadata fields instead of only using built-in types. Any invalid metadata
|
| 762 |
+
will cause :exc:`InvalidMetadata` to be raised (with a
|
| 763 |
+
:py:attr:`~BaseException.__cause__` attribute as appropriate).
|
| 764 |
+
"""
|
| 765 |
+
|
| 766 |
+
_raw: RawMetadata
|
| 767 |
+
|
| 768 |
+
@classmethod
|
| 769 |
+
def from_raw(cls, data: RawMetadata, *, validate: bool = True) -> Metadata:
|
| 770 |
+
"""Create an instance from :class:`RawMetadata`.
|
| 771 |
+
|
| 772 |
+
If *validate* is true, all metadata will be validated. All exceptions
|
| 773 |
+
related to validation will be gathered and raised as an :class:`ExceptionGroup`.
|
| 774 |
+
"""
|
| 775 |
+
ins = cls()
|
| 776 |
+
ins._raw = data.copy() # Mutations occur due to caching enriched values.
|
| 777 |
+
|
| 778 |
+
if validate:
|
| 779 |
+
collector = _ErrorCollector()
|
| 780 |
+
metadata_version = None
|
| 781 |
+
with collector.collect(InvalidMetadata):
|
| 782 |
+
metadata_version = ins.metadata_version
|
| 783 |
+
metadata_age = _VALID_METADATA_VERSIONS.index(metadata_version)
|
| 784 |
+
|
| 785 |
+
# Make sure to check for the fields that are present, the required
|
| 786 |
+
# fields (so their absence can be reported).
|
| 787 |
+
fields_to_check = frozenset(ins._raw) | _REQUIRED_ATTRS
|
| 788 |
+
# Remove fields that have already been checked.
|
| 789 |
+
fields_to_check -= {"metadata_version"}
|
| 790 |
+
|
| 791 |
+
for key in fields_to_check:
|
| 792 |
+
try:
|
| 793 |
+
if metadata_version:
|
| 794 |
+
# Can't use getattr() as that triggers descriptor protocol which
|
| 795 |
+
# will fail due to no value for the instance argument.
|
| 796 |
+
try:
|
| 797 |
+
field_metadata_version = cls.__dict__[key].added
|
| 798 |
+
except KeyError:
|
| 799 |
+
exc = InvalidMetadata(key, f"unrecognized field: {key!r}")
|
| 800 |
+
collector.error(exc)
|
| 801 |
+
continue
|
| 802 |
+
field_age = _VALID_METADATA_VERSIONS.index(
|
| 803 |
+
field_metadata_version
|
| 804 |
+
)
|
| 805 |
+
if field_age > metadata_age:
|
| 806 |
+
field = _RAW_TO_EMAIL_MAPPING[key]
|
| 807 |
+
exc = InvalidMetadata(
|
| 808 |
+
field,
|
| 809 |
+
f"{field} introduced in metadata version "
|
| 810 |
+
f"{field_metadata_version}, not {metadata_version}",
|
| 811 |
+
)
|
| 812 |
+
collector.error(exc)
|
| 813 |
+
continue
|
| 814 |
+
getattr(ins, key)
|
| 815 |
+
except InvalidMetadata as exc:
|
| 816 |
+
collector.error(exc)
|
| 817 |
+
|
| 818 |
+
collector.finalize("invalid metadata")
|
| 819 |
+
|
| 820 |
+
return ins
|
| 821 |
+
|
| 822 |
+
@classmethod
|
| 823 |
+
def from_email(cls, data: bytes | str, *, validate: bool = True) -> Metadata:
|
| 824 |
+
"""Parse metadata from email headers.
|
| 825 |
+
|
| 826 |
+
If *validate* is true, the metadata will be validated. All exceptions
|
| 827 |
+
related to validation will be gathered and raised as an :class:`ExceptionGroup`.
|
| 828 |
+
"""
|
| 829 |
+
raw, unparsed = parse_email(data)
|
| 830 |
+
|
| 831 |
+
if validate:
|
| 832 |
+
with _ErrorCollector().on_exit("unparsed") as collector:
|
| 833 |
+
for unparsed_key in unparsed:
|
| 834 |
+
if unparsed_key in _EMAIL_TO_RAW_MAPPING:
|
| 835 |
+
message = f"{unparsed_key!r} has invalid data"
|
| 836 |
+
else:
|
| 837 |
+
message = f"unrecognized field: {unparsed_key!r}"
|
| 838 |
+
collector.error(InvalidMetadata(unparsed_key, message))
|
| 839 |
+
|
| 840 |
+
try:
|
| 841 |
+
return cls.from_raw(raw, validate=validate)
|
| 842 |
+
except ExceptionGroup as exc_group:
|
| 843 |
+
raise ExceptionGroup(
|
| 844 |
+
"invalid or unparsed metadata", exc_group.exceptions
|
| 845 |
+
) from None
|
| 846 |
+
|
| 847 |
+
metadata_version: _Validator[_MetadataVersion] = _Validator()
|
| 848 |
+
""":external:ref:`core-metadata-metadata-version`
|
| 849 |
+
(required; validated to be a valid metadata version)"""
|
| 850 |
+
# `name` is not normalized/typed to NormalizedName so as to provide access to
|
| 851 |
+
# the original/raw name.
|
| 852 |
+
name: _Validator[str] = _Validator()
|
| 853 |
+
""":external:ref:`core-metadata-name`
|
| 854 |
+
(required; validated using :func:`~packaging.utils.canonicalize_name` and its
|
| 855 |
+
*validate* parameter)"""
|
| 856 |
+
version: _Validator[version_module.Version] = _Validator()
|
| 857 |
+
""":external:ref:`core-metadata-version` (required)"""
|
| 858 |
+
dynamic: _Validator[list[str] | None] = _Validator(
|
| 859 |
+
added="2.2",
|
| 860 |
+
)
|
| 861 |
+
""":external:ref:`core-metadata-dynamic`
|
| 862 |
+
(validated against core metadata field names and lowercased)"""
|
| 863 |
+
platforms: _Validator[list[str] | None] = _Validator()
|
| 864 |
+
""":external:ref:`core-metadata-platform`"""
|
| 865 |
+
supported_platforms: _Validator[list[str] | None] = _Validator(added="1.1")
|
| 866 |
+
""":external:ref:`core-metadata-supported-platform`"""
|
| 867 |
+
summary: _Validator[str | None] = _Validator()
|
| 868 |
+
""":external:ref:`core-metadata-summary` (validated to contain no newlines)"""
|
| 869 |
+
description: _Validator[str | None] = _Validator() # TODO 2.1: can be in body
|
| 870 |
+
""":external:ref:`core-metadata-description`"""
|
| 871 |
+
description_content_type: _Validator[str | None] = _Validator(added="2.1")
|
| 872 |
+
""":external:ref:`core-metadata-description-content-type` (validated)"""
|
| 873 |
+
keywords: _Validator[list[str] | None] = _Validator()
|
| 874 |
+
""":external:ref:`core-metadata-keywords`"""
|
| 875 |
+
home_page: _Validator[str | None] = _Validator()
|
| 876 |
+
""":external:ref:`core-metadata-home-page`"""
|
| 877 |
+
download_url: _Validator[str | None] = _Validator(added="1.1")
|
| 878 |
+
""":external:ref:`core-metadata-download-url`"""
|
| 879 |
+
author: _Validator[str | None] = _Validator()
|
| 880 |
+
""":external:ref:`core-metadata-author`"""
|
| 881 |
+
author_email: _Validator[str | None] = _Validator()
|
| 882 |
+
""":external:ref:`core-metadata-author-email`"""
|
| 883 |
+
maintainer: _Validator[str | None] = _Validator(added="1.2")
|
| 884 |
+
""":external:ref:`core-metadata-maintainer`"""
|
| 885 |
+
maintainer_email: _Validator[str | None] = _Validator(added="1.2")
|
| 886 |
+
""":external:ref:`core-metadata-maintainer-email`"""
|
| 887 |
+
license: _Validator[str | None] = _Validator()
|
| 888 |
+
""":external:ref:`core-metadata-license`"""
|
| 889 |
+
license_expression: _Validator[NormalizedLicenseExpression | None] = _Validator(
|
| 890 |
+
added="2.4"
|
| 891 |
+
)
|
| 892 |
+
""":external:ref:`core-metadata-license-expression`"""
|
| 893 |
+
license_files: _Validator[list[str] | None] = _Validator(added="2.4")
|
| 894 |
+
""":external:ref:`core-metadata-license-file`"""
|
| 895 |
+
classifiers: _Validator[list[str] | None] = _Validator(added="1.1")
|
| 896 |
+
""":external:ref:`core-metadata-classifier`"""
|
| 897 |
+
requires_dist: _Validator[list[requirements.Requirement] | None] = _Validator(
|
| 898 |
+
added="1.2"
|
| 899 |
+
)
|
| 900 |
+
""":external:ref:`core-metadata-requires-dist`"""
|
| 901 |
+
requires_python: _Validator[specifiers.SpecifierSet | None] = _Validator(
|
| 902 |
+
added="1.2"
|
| 903 |
+
)
|
| 904 |
+
""":external:ref:`core-metadata-requires-python`"""
|
| 905 |
+
# Because `Requires-External` allows for non-PEP 440 version specifiers, we
|
| 906 |
+
# don't do any processing on the values.
|
| 907 |
+
requires_external: _Validator[list[str] | None] = _Validator(added="1.2")
|
| 908 |
+
""":external:ref:`core-metadata-requires-external`"""
|
| 909 |
+
project_urls: _Validator[dict[str, str] | None] = _Validator(added="1.2")
|
| 910 |
+
""":external:ref:`core-metadata-project-url`"""
|
| 911 |
+
# PEP 685 lets us raise an error if an extra doesn't pass `Name` validation
|
| 912 |
+
# regardless of metadata version.
|
| 913 |
+
provides_extra: _Validator[list[utils.NormalizedName] | None] = _Validator(
|
| 914 |
+
added="2.1",
|
| 915 |
+
)
|
| 916 |
+
""":external:ref:`core-metadata-provides-extra`"""
|
| 917 |
+
provides_dist: _Validator[list[str] | None] = _Validator(added="1.2")
|
| 918 |
+
""":external:ref:`core-metadata-provides-dist`"""
|
| 919 |
+
obsoletes_dist: _Validator[list[str] | None] = _Validator(added="1.2")
|
| 920 |
+
""":external:ref:`core-metadata-obsoletes-dist`"""
|
| 921 |
+
import_names: _Validator[list[str] | None] = _Validator(added="2.5")
|
| 922 |
+
""":external:ref:`core-metadata-import-name`"""
|
| 923 |
+
import_namespaces: _Validator[list[str] | None] = _Validator(added="2.5")
|
| 924 |
+
""":external:ref:`core-metadata-import-namespace`"""
|
| 925 |
+
requires: _Validator[list[str] | None] = _Validator(added="1.1")
|
| 926 |
+
"""``Requires`` (deprecated)"""
|
| 927 |
+
provides: _Validator[list[str] | None] = _Validator(added="1.1")
|
| 928 |
+
"""``Provides`` (deprecated)"""
|
| 929 |
+
obsoletes: _Validator[list[str] | None] = _Validator(added="1.1")
|
| 930 |
+
"""``Obsoletes`` (deprecated)"""
|
| 931 |
+
|
| 932 |
+
def as_rfc822(self) -> RFC822Message:
|
| 933 |
+
"""
|
| 934 |
+
Return an RFC822 message with the metadata.
|
| 935 |
+
"""
|
| 936 |
+
message = RFC822Message()
|
| 937 |
+
self._write_metadata(message)
|
| 938 |
+
return message
|
| 939 |
+
|
| 940 |
+
def _write_metadata(self, message: RFC822Message) -> None:
|
| 941 |
+
"""
|
| 942 |
+
Return an RFC822 message with the metadata.
|
| 943 |
+
"""
|
| 944 |
+
for name, validator in self.__class__.__dict__.items():
|
| 945 |
+
if isinstance(validator, _Validator) and name != "description":
|
| 946 |
+
value = getattr(self, name)
|
| 947 |
+
email_name = _RAW_TO_EMAIL_MAPPING[name]
|
| 948 |
+
if value is not None:
|
| 949 |
+
if email_name == "project-url":
|
| 950 |
+
for label, url in value.items():
|
| 951 |
+
message[email_name] = f"{label}, {url}"
|
| 952 |
+
elif email_name == "keywords":
|
| 953 |
+
message[email_name] = ",".join(value)
|
| 954 |
+
elif email_name == "import-name" and value == []:
|
| 955 |
+
message[email_name] = ""
|
| 956 |
+
elif isinstance(value, list):
|
| 957 |
+
for item in value:
|
| 958 |
+
message[email_name] = str(item)
|
| 959 |
+
else:
|
| 960 |
+
message[email_name] = str(value)
|
| 961 |
+
|
| 962 |
+
# The description is a special case because it is in the body of the message.
|
| 963 |
+
if self.description is not None:
|
| 964 |
+
message.set_payload(self.description)
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/py.typed
ADDED
|
File without changes
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/pylock.py
ADDED
|
@@ -0,0 +1,905 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import dataclasses
|
| 4 |
+
import logging
|
| 5 |
+
import re
|
| 6 |
+
from collections.abc import Mapping, Sequence
|
| 7 |
+
from dataclasses import dataclass
|
| 8 |
+
from datetime import datetime
|
| 9 |
+
from typing import (
|
| 10 |
+
TYPE_CHECKING,
|
| 11 |
+
Any,
|
| 12 |
+
Callable,
|
| 13 |
+
Protocol,
|
| 14 |
+
TypeVar,
|
| 15 |
+
cast,
|
| 16 |
+
)
|
| 17 |
+
from urllib.parse import urlparse
|
| 18 |
+
|
| 19 |
+
from .markers import Environment, Marker, default_environment
|
| 20 |
+
from .specifiers import SpecifierSet
|
| 21 |
+
from .tags import create_compatible_tags_selector, sys_tags
|
| 22 |
+
from .utils import (
|
| 23 |
+
NormalizedName,
|
| 24 |
+
is_normalized_name,
|
| 25 |
+
parse_sdist_filename,
|
| 26 |
+
parse_wheel_filename,
|
| 27 |
+
)
|
| 28 |
+
from .version import Version
|
| 29 |
+
|
| 30 |
+
if TYPE_CHECKING: # pragma: no cover
|
| 31 |
+
from collections.abc import Collection, Iterator
|
| 32 |
+
from pathlib import Path
|
| 33 |
+
|
| 34 |
+
from typing_extensions import Self
|
| 35 |
+
|
| 36 |
+
from .tags import Tag
|
| 37 |
+
|
| 38 |
+
_logger = logging.getLogger(__name__)
|
| 39 |
+
|
| 40 |
+
__all__ = [
|
| 41 |
+
"Package",
|
| 42 |
+
"PackageArchive",
|
| 43 |
+
"PackageDirectory",
|
| 44 |
+
"PackageSdist",
|
| 45 |
+
"PackageVcs",
|
| 46 |
+
"PackageWheel",
|
| 47 |
+
"Pylock",
|
| 48 |
+
"PylockUnsupportedVersionError",
|
| 49 |
+
"PylockValidationError",
|
| 50 |
+
"is_valid_pylock_path",
|
| 51 |
+
]
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def __dir__() -> list[str]:
|
| 55 |
+
return __all__
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
_T = TypeVar("_T")
|
| 59 |
+
_T2 = TypeVar("_T2")
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
class _FromMappingProtocol(Protocol): # pragma: no cover
|
| 63 |
+
@classmethod
|
| 64 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self: ...
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
_FromMappingProtocolT = TypeVar("_FromMappingProtocolT", bound=_FromMappingProtocol)
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
_PYLOCK_FILE_NAME_RE = re.compile(r"^pylock\.([^.]+)\.toml$")
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def is_valid_pylock_path(path: Path) -> bool:
|
| 74 |
+
"""Check if the given path is a valid pylock file path."""
|
| 75 |
+
return path.name == "pylock.toml" or bool(_PYLOCK_FILE_NAME_RE.match(path.name))
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def _toml_key(key: str) -> str:
|
| 79 |
+
return key.replace("_", "-")
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def _toml_value(key: str, value: Any) -> Any: # noqa: ANN401
|
| 83 |
+
if isinstance(value, (Version, Marker, SpecifierSet)):
|
| 84 |
+
return str(value)
|
| 85 |
+
if isinstance(value, Sequence) and key == "environments":
|
| 86 |
+
return [str(v) for v in value]
|
| 87 |
+
return value
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def _toml_dict_factory(data: list[tuple[str, Any]]) -> dict[str, Any]:
|
| 91 |
+
return {
|
| 92 |
+
_toml_key(key): _toml_value(key, value)
|
| 93 |
+
for key, value in data
|
| 94 |
+
if value is not None
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def _get(d: Mapping[str, Any], expected_type: type[_T], key: str) -> _T | None:
|
| 99 |
+
"""Get a value from the dictionary and verify it's the expected type."""
|
| 100 |
+
if (value := d.get(key)) is None:
|
| 101 |
+
return None
|
| 102 |
+
if not isinstance(value, expected_type):
|
| 103 |
+
raise PylockValidationError(
|
| 104 |
+
f"Unexpected type {type(value).__name__} "
|
| 105 |
+
f"(expected {expected_type.__name__})",
|
| 106 |
+
context=key,
|
| 107 |
+
)
|
| 108 |
+
return value
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def _get_required(d: Mapping[str, Any], expected_type: type[_T], key: str) -> _T:
|
| 112 |
+
"""Get a required value from the dictionary and verify it's the expected type."""
|
| 113 |
+
if (value := _get(d, expected_type, key)) is None:
|
| 114 |
+
raise _PylockRequiredKeyError(key)
|
| 115 |
+
return value
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def _get_sequence(
|
| 119 |
+
d: Mapping[str, Any], expected_item_type: type[_T], key: str
|
| 120 |
+
) -> Sequence[_T] | None:
|
| 121 |
+
"""Get a list value from the dictionary and verify it's the expected items type."""
|
| 122 |
+
if (value := _get(d, Sequence, key)) is None: # type: ignore[type-abstract]
|
| 123 |
+
return None
|
| 124 |
+
if isinstance(value, (str, bytes)):
|
| 125 |
+
# special case: str and bytes are Sequences, but we want to reject it
|
| 126 |
+
raise PylockValidationError(
|
| 127 |
+
f"Unexpected type {type(value).__name__} (expected Sequence)",
|
| 128 |
+
context=key,
|
| 129 |
+
)
|
| 130 |
+
for i, item in enumerate(value):
|
| 131 |
+
if not isinstance(item, expected_item_type):
|
| 132 |
+
raise PylockValidationError(
|
| 133 |
+
f"Unexpected type {type(item).__name__} "
|
| 134 |
+
f"(expected {expected_item_type.__name__})",
|
| 135 |
+
context=f"{key}[{i}]",
|
| 136 |
+
)
|
| 137 |
+
return value
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
def _get_as(
|
| 141 |
+
d: Mapping[str, Any],
|
| 142 |
+
expected_type: type[_T],
|
| 143 |
+
target_type: Callable[[_T], _T2],
|
| 144 |
+
key: str,
|
| 145 |
+
) -> _T2 | None:
|
| 146 |
+
"""Get a value from the dictionary, verify it's the expected type,
|
| 147 |
+
and convert to the target type.
|
| 148 |
+
|
| 149 |
+
This assumes the target_type constructor accepts the value.
|
| 150 |
+
"""
|
| 151 |
+
if (value := _get(d, expected_type, key)) is None:
|
| 152 |
+
return None
|
| 153 |
+
try:
|
| 154 |
+
return target_type(value)
|
| 155 |
+
except Exception as e:
|
| 156 |
+
raise PylockValidationError(e, context=key) from e
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
def _get_required_as(
|
| 160 |
+
d: Mapping[str, Any],
|
| 161 |
+
expected_type: type[_T],
|
| 162 |
+
target_type: Callable[[_T], _T2],
|
| 163 |
+
key: str,
|
| 164 |
+
) -> _T2:
|
| 165 |
+
"""Get a required value from the dict, verify it's the expected type,
|
| 166 |
+
and convert to the target type."""
|
| 167 |
+
if (value := _get_as(d, expected_type, target_type, key)) is None:
|
| 168 |
+
raise _PylockRequiredKeyError(key)
|
| 169 |
+
return value
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def _get_sequence_as(
|
| 173 |
+
d: Mapping[str, Any],
|
| 174 |
+
expected_item_type: type[_T],
|
| 175 |
+
target_item_type: Callable[[_T], _T2],
|
| 176 |
+
key: str,
|
| 177 |
+
) -> list[_T2] | None:
|
| 178 |
+
"""Get list value from dictionary and verify expected items type."""
|
| 179 |
+
if (value := _get_sequence(d, expected_item_type, key)) is None:
|
| 180 |
+
return None
|
| 181 |
+
result = []
|
| 182 |
+
try:
|
| 183 |
+
for item in value:
|
| 184 |
+
typed_item = target_item_type(item)
|
| 185 |
+
result.append(typed_item)
|
| 186 |
+
except Exception as e:
|
| 187 |
+
raise PylockValidationError(e, context=f"{key}[{len(result)}]") from e
|
| 188 |
+
return result
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
def _get_object(
|
| 192 |
+
d: Mapping[str, Any], target_type: type[_FromMappingProtocolT], key: str
|
| 193 |
+
) -> _FromMappingProtocolT | None:
|
| 194 |
+
"""Get a dictionary value from the dictionary and convert it to a dataclass."""
|
| 195 |
+
if (value := _get(d, Mapping, key)) is None: # type: ignore[type-abstract]
|
| 196 |
+
return None
|
| 197 |
+
try:
|
| 198 |
+
return target_type._from_dict(value)
|
| 199 |
+
except Exception as e:
|
| 200 |
+
raise PylockValidationError(e, context=key) from e
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
def _get_sequence_of_objects(
|
| 204 |
+
d: Mapping[str, Any], target_item_type: type[_FromMappingProtocolT], key: str
|
| 205 |
+
) -> list[_FromMappingProtocolT] | None:
|
| 206 |
+
"""Get a list value from the dictionary and convert its items to a dataclass."""
|
| 207 |
+
if (value := _get_sequence(d, Mapping, key)) is None: # type: ignore[type-abstract]
|
| 208 |
+
return None
|
| 209 |
+
result: list[_FromMappingProtocolT] = []
|
| 210 |
+
try:
|
| 211 |
+
for item in value:
|
| 212 |
+
typed_item = target_item_type._from_dict(item)
|
| 213 |
+
result.append(typed_item)
|
| 214 |
+
except Exception as e:
|
| 215 |
+
raise PylockValidationError(e, context=f"{key}[{len(result)}]") from e
|
| 216 |
+
return result
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
def _get_required_sequence_of_objects(
|
| 220 |
+
d: Mapping[str, Any], target_item_type: type[_FromMappingProtocolT], key: str
|
| 221 |
+
) -> Sequence[_FromMappingProtocolT]:
|
| 222 |
+
"""Get a required list value from the dictionary and convert its items to a
|
| 223 |
+
dataclass."""
|
| 224 |
+
if (result := _get_sequence_of_objects(d, target_item_type, key)) is None:
|
| 225 |
+
raise _PylockRequiredKeyError(key)
|
| 226 |
+
return result
|
| 227 |
+
|
| 228 |
+
|
| 229 |
+
def _validate_normalized_name(name: str) -> NormalizedName:
|
| 230 |
+
"""Validate that a string is a NormalizedName."""
|
| 231 |
+
if not is_normalized_name(name):
|
| 232 |
+
raise PylockValidationError(f"Name {name!r} is not normalized")
|
| 233 |
+
return NormalizedName(name)
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
def _validate_path_url(path: str | None, url: str | None) -> None:
|
| 237 |
+
if not path and not url:
|
| 238 |
+
raise PylockValidationError("path or url must be provided")
|
| 239 |
+
|
| 240 |
+
|
| 241 |
+
def _path_name(path: str | None) -> str | None:
|
| 242 |
+
if not path:
|
| 243 |
+
return None
|
| 244 |
+
# If the path is relative it MAY use POSIX-style path separators explicitly
|
| 245 |
+
# for portability
|
| 246 |
+
if "/" in path:
|
| 247 |
+
return path.rsplit("/", 1)[-1]
|
| 248 |
+
elif "\\" in path:
|
| 249 |
+
return path.rsplit("\\", 1)[-1]
|
| 250 |
+
else:
|
| 251 |
+
return path
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
def _url_name(url: str | None) -> str | None:
|
| 255 |
+
if not url:
|
| 256 |
+
return None
|
| 257 |
+
url_path = urlparse(url).path
|
| 258 |
+
return url_path.rsplit("/", 1)[-1]
|
| 259 |
+
|
| 260 |
+
|
| 261 |
+
def _validate_hashes(hashes: Mapping[str, Any]) -> Mapping[str, Any]:
|
| 262 |
+
if not hashes:
|
| 263 |
+
raise PylockValidationError("At least one hash must be provided")
|
| 264 |
+
if not all(isinstance(hash_val, str) for hash_val in hashes.values()):
|
| 265 |
+
raise PylockValidationError("Hash values must be strings")
|
| 266 |
+
return hashes
|
| 267 |
+
|
| 268 |
+
|
| 269 |
+
class PylockValidationError(Exception):
|
| 270 |
+
"""Raised when when input data is not spec-compliant."""
|
| 271 |
+
|
| 272 |
+
context: str | None = None
|
| 273 |
+
message: str
|
| 274 |
+
|
| 275 |
+
def __init__(
|
| 276 |
+
self,
|
| 277 |
+
cause: str | Exception,
|
| 278 |
+
*,
|
| 279 |
+
context: str | None = None,
|
| 280 |
+
) -> None:
|
| 281 |
+
if isinstance(cause, PylockValidationError):
|
| 282 |
+
if cause.context:
|
| 283 |
+
self.context = (
|
| 284 |
+
f"{context}.{cause.context}" if context else cause.context
|
| 285 |
+
)
|
| 286 |
+
else:
|
| 287 |
+
self.context = context
|
| 288 |
+
self.message = cause.message
|
| 289 |
+
else:
|
| 290 |
+
self.context = context
|
| 291 |
+
self.message = str(cause)
|
| 292 |
+
|
| 293 |
+
def __str__(self) -> str:
|
| 294 |
+
if self.context:
|
| 295 |
+
return f"{self.message} in {self.context!r}"
|
| 296 |
+
return self.message
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
class _PylockRequiredKeyError(PylockValidationError):
|
| 300 |
+
def __init__(self, key: str) -> None:
|
| 301 |
+
super().__init__("Missing required value", context=key)
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
class PylockUnsupportedVersionError(PylockValidationError):
|
| 305 |
+
"""Raised when encountering an unsupported `lock_version`."""
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
class PylockSelectError(Exception):
|
| 309 |
+
"""Base exception for errors raised by :meth:`Pylock.select`."""
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
@dataclass(frozen=True, init=False)
|
| 313 |
+
class PackageVcs:
|
| 314 |
+
type: str
|
| 315 |
+
url: str | None = None
|
| 316 |
+
path: str | None = None
|
| 317 |
+
requested_revision: str | None = None
|
| 318 |
+
commit_id: str # type: ignore[misc]
|
| 319 |
+
subdirectory: str | None = None
|
| 320 |
+
|
| 321 |
+
def __init__(
|
| 322 |
+
self,
|
| 323 |
+
*,
|
| 324 |
+
type: str,
|
| 325 |
+
url: str | None = None,
|
| 326 |
+
path: str | None = None,
|
| 327 |
+
requested_revision: str | None = None,
|
| 328 |
+
commit_id: str,
|
| 329 |
+
subdirectory: str | None = None,
|
| 330 |
+
) -> None:
|
| 331 |
+
# In Python 3.10+ make dataclass kw_only=True and remove __init__
|
| 332 |
+
object.__setattr__(self, "type", type)
|
| 333 |
+
object.__setattr__(self, "url", url)
|
| 334 |
+
object.__setattr__(self, "path", path)
|
| 335 |
+
object.__setattr__(self, "requested_revision", requested_revision)
|
| 336 |
+
object.__setattr__(self, "commit_id", commit_id)
|
| 337 |
+
object.__setattr__(self, "subdirectory", subdirectory)
|
| 338 |
+
|
| 339 |
+
@classmethod
|
| 340 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self:
|
| 341 |
+
package_vcs = cls(
|
| 342 |
+
type=_get_required(d, str, "type"),
|
| 343 |
+
url=_get(d, str, "url"),
|
| 344 |
+
path=_get(d, str, "path"),
|
| 345 |
+
requested_revision=_get(d, str, "requested-revision"),
|
| 346 |
+
commit_id=_get_required(d, str, "commit-id"),
|
| 347 |
+
subdirectory=_get(d, str, "subdirectory"),
|
| 348 |
+
)
|
| 349 |
+
_validate_path_url(package_vcs.path, package_vcs.url)
|
| 350 |
+
return package_vcs
|
| 351 |
+
|
| 352 |
+
|
| 353 |
+
@dataclass(frozen=True, init=False)
|
| 354 |
+
class PackageDirectory:
|
| 355 |
+
path: str
|
| 356 |
+
editable: bool | None = None
|
| 357 |
+
subdirectory: str | None = None
|
| 358 |
+
|
| 359 |
+
def __init__(
|
| 360 |
+
self,
|
| 361 |
+
*,
|
| 362 |
+
path: str,
|
| 363 |
+
editable: bool | None = None,
|
| 364 |
+
subdirectory: str | None = None,
|
| 365 |
+
) -> None:
|
| 366 |
+
# In Python 3.10+ make dataclass kw_only=True and remove __init__
|
| 367 |
+
object.__setattr__(self, "path", path)
|
| 368 |
+
object.__setattr__(self, "editable", editable)
|
| 369 |
+
object.__setattr__(self, "subdirectory", subdirectory)
|
| 370 |
+
|
| 371 |
+
@classmethod
|
| 372 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self:
|
| 373 |
+
return cls(
|
| 374 |
+
path=_get_required(d, str, "path"),
|
| 375 |
+
editable=_get(d, bool, "editable"),
|
| 376 |
+
subdirectory=_get(d, str, "subdirectory"),
|
| 377 |
+
)
|
| 378 |
+
|
| 379 |
+
|
| 380 |
+
@dataclass(frozen=True, init=False)
|
| 381 |
+
class PackageArchive:
|
| 382 |
+
url: str | None = None
|
| 383 |
+
path: str | None = None
|
| 384 |
+
size: int | None = None
|
| 385 |
+
upload_time: datetime | None = None
|
| 386 |
+
hashes: Mapping[str, str] # type: ignore[misc]
|
| 387 |
+
subdirectory: str | None = None
|
| 388 |
+
|
| 389 |
+
def __init__(
|
| 390 |
+
self,
|
| 391 |
+
*,
|
| 392 |
+
url: str | None = None,
|
| 393 |
+
path: str | None = None,
|
| 394 |
+
size: int | None = None,
|
| 395 |
+
upload_time: datetime | None = None,
|
| 396 |
+
hashes: Mapping[str, str],
|
| 397 |
+
subdirectory: str | None = None,
|
| 398 |
+
) -> None:
|
| 399 |
+
# In Python 3.10+ make dataclass kw_only=True and remove __init__
|
| 400 |
+
object.__setattr__(self, "url", url)
|
| 401 |
+
object.__setattr__(self, "path", path)
|
| 402 |
+
object.__setattr__(self, "size", size)
|
| 403 |
+
object.__setattr__(self, "upload_time", upload_time)
|
| 404 |
+
object.__setattr__(self, "hashes", hashes)
|
| 405 |
+
object.__setattr__(self, "subdirectory", subdirectory)
|
| 406 |
+
|
| 407 |
+
@classmethod
|
| 408 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self:
|
| 409 |
+
package_archive = cls(
|
| 410 |
+
url=_get(d, str, "url"),
|
| 411 |
+
path=_get(d, str, "path"),
|
| 412 |
+
size=_get(d, int, "size"),
|
| 413 |
+
upload_time=_get(d, datetime, "upload-time"),
|
| 414 |
+
hashes=_get_required_as(d, Mapping, _validate_hashes, "hashes"), # type: ignore[type-abstract]
|
| 415 |
+
subdirectory=_get(d, str, "subdirectory"),
|
| 416 |
+
)
|
| 417 |
+
_validate_path_url(package_archive.path, package_archive.url)
|
| 418 |
+
return package_archive
|
| 419 |
+
|
| 420 |
+
|
| 421 |
+
@dataclass(frozen=True, init=False)
|
| 422 |
+
class PackageSdist:
|
| 423 |
+
name: str | None = None
|
| 424 |
+
upload_time: datetime | None = None
|
| 425 |
+
url: str | None = None
|
| 426 |
+
path: str | None = None
|
| 427 |
+
size: int | None = None
|
| 428 |
+
hashes: Mapping[str, str] # type: ignore[misc]
|
| 429 |
+
|
| 430 |
+
def __init__(
|
| 431 |
+
self,
|
| 432 |
+
*,
|
| 433 |
+
name: str | None = None,
|
| 434 |
+
upload_time: datetime | None = None,
|
| 435 |
+
url: str | None = None,
|
| 436 |
+
path: str | None = None,
|
| 437 |
+
size: int | None = None,
|
| 438 |
+
hashes: Mapping[str, str],
|
| 439 |
+
) -> None:
|
| 440 |
+
# In Python 3.10+ make dataclass kw_only=True and remove __init__
|
| 441 |
+
object.__setattr__(self, "name", name)
|
| 442 |
+
object.__setattr__(self, "upload_time", upload_time)
|
| 443 |
+
object.__setattr__(self, "url", url)
|
| 444 |
+
object.__setattr__(self, "path", path)
|
| 445 |
+
object.__setattr__(self, "size", size)
|
| 446 |
+
object.__setattr__(self, "hashes", hashes)
|
| 447 |
+
|
| 448 |
+
@classmethod
|
| 449 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self:
|
| 450 |
+
package_sdist = cls(
|
| 451 |
+
name=_get(d, str, "name"),
|
| 452 |
+
upload_time=_get(d, datetime, "upload-time"),
|
| 453 |
+
url=_get(d, str, "url"),
|
| 454 |
+
path=_get(d, str, "path"),
|
| 455 |
+
size=_get(d, int, "size"),
|
| 456 |
+
hashes=_get_required_as(d, Mapping, _validate_hashes, "hashes"), # type: ignore[type-abstract]
|
| 457 |
+
)
|
| 458 |
+
_validate_path_url(package_sdist.path, package_sdist.url)
|
| 459 |
+
return package_sdist
|
| 460 |
+
|
| 461 |
+
@property
|
| 462 |
+
def filename(self) -> str:
|
| 463 |
+
"""Get the filename of the sdist."""
|
| 464 |
+
filename = self.name or _path_name(self.path) or _url_name(self.url)
|
| 465 |
+
if not filename:
|
| 466 |
+
raise PylockValidationError("Cannot determine sdist filename")
|
| 467 |
+
return filename
|
| 468 |
+
|
| 469 |
+
|
| 470 |
+
@dataclass(frozen=True, init=False)
|
| 471 |
+
class PackageWheel:
|
| 472 |
+
name: str | None = None
|
| 473 |
+
upload_time: datetime | None = None
|
| 474 |
+
url: str | None = None
|
| 475 |
+
path: str | None = None
|
| 476 |
+
size: int | None = None
|
| 477 |
+
hashes: Mapping[str, str] # type: ignore[misc]
|
| 478 |
+
|
| 479 |
+
def __init__(
|
| 480 |
+
self,
|
| 481 |
+
*,
|
| 482 |
+
name: str | None = None,
|
| 483 |
+
upload_time: datetime | None = None,
|
| 484 |
+
url: str | None = None,
|
| 485 |
+
path: str | None = None,
|
| 486 |
+
size: int | None = None,
|
| 487 |
+
hashes: Mapping[str, str],
|
| 488 |
+
) -> None:
|
| 489 |
+
# In Python 3.10+ make dataclass kw_only=True and remove __init__
|
| 490 |
+
object.__setattr__(self, "name", name)
|
| 491 |
+
object.__setattr__(self, "upload_time", upload_time)
|
| 492 |
+
object.__setattr__(self, "url", url)
|
| 493 |
+
object.__setattr__(self, "path", path)
|
| 494 |
+
object.__setattr__(self, "size", size)
|
| 495 |
+
object.__setattr__(self, "hashes", hashes)
|
| 496 |
+
|
| 497 |
+
@classmethod
|
| 498 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self:
|
| 499 |
+
package_wheel = cls(
|
| 500 |
+
name=_get(d, str, "name"),
|
| 501 |
+
upload_time=_get(d, datetime, "upload-time"),
|
| 502 |
+
url=_get(d, str, "url"),
|
| 503 |
+
path=_get(d, str, "path"),
|
| 504 |
+
size=_get(d, int, "size"),
|
| 505 |
+
hashes=_get_required_as(d, Mapping, _validate_hashes, "hashes"), # type: ignore[type-abstract]
|
| 506 |
+
)
|
| 507 |
+
_validate_path_url(package_wheel.path, package_wheel.url)
|
| 508 |
+
return package_wheel
|
| 509 |
+
|
| 510 |
+
@property
|
| 511 |
+
def filename(self) -> str:
|
| 512 |
+
"""Get the filename of the wheel."""
|
| 513 |
+
filename = self.name or _path_name(self.path) or _url_name(self.url)
|
| 514 |
+
if not filename:
|
| 515 |
+
raise PylockValidationError("Cannot determine wheel filename")
|
| 516 |
+
return filename
|
| 517 |
+
|
| 518 |
+
|
| 519 |
+
@dataclass(frozen=True, init=False)
|
| 520 |
+
class Package:
|
| 521 |
+
name: NormalizedName
|
| 522 |
+
version: Version | None = None
|
| 523 |
+
marker: Marker | None = None
|
| 524 |
+
requires_python: SpecifierSet | None = None
|
| 525 |
+
dependencies: Sequence[Mapping[str, Any]] | None = None
|
| 526 |
+
vcs: PackageVcs | None = None
|
| 527 |
+
directory: PackageDirectory | None = None
|
| 528 |
+
archive: PackageArchive | None = None
|
| 529 |
+
index: str | None = None
|
| 530 |
+
sdist: PackageSdist | None = None
|
| 531 |
+
wheels: Sequence[PackageWheel] | None = None
|
| 532 |
+
attestation_identities: Sequence[Mapping[str, Any]] | None = None
|
| 533 |
+
tool: Mapping[str, Any] | None = None
|
| 534 |
+
|
| 535 |
+
def __init__(
|
| 536 |
+
self,
|
| 537 |
+
*,
|
| 538 |
+
name: NormalizedName,
|
| 539 |
+
version: Version | None = None,
|
| 540 |
+
marker: Marker | None = None,
|
| 541 |
+
requires_python: SpecifierSet | None = None,
|
| 542 |
+
dependencies: Sequence[Mapping[str, Any]] | None = None,
|
| 543 |
+
vcs: PackageVcs | None = None,
|
| 544 |
+
directory: PackageDirectory | None = None,
|
| 545 |
+
archive: PackageArchive | None = None,
|
| 546 |
+
index: str | None = None,
|
| 547 |
+
sdist: PackageSdist | None = None,
|
| 548 |
+
wheels: Sequence[PackageWheel] | None = None,
|
| 549 |
+
attestation_identities: Sequence[Mapping[str, Any]] | None = None,
|
| 550 |
+
tool: Mapping[str, Any] | None = None,
|
| 551 |
+
) -> None:
|
| 552 |
+
# In Python 3.10+ make dataclass kw_only=True and remove __init__
|
| 553 |
+
object.__setattr__(self, "name", name)
|
| 554 |
+
object.__setattr__(self, "version", version)
|
| 555 |
+
object.__setattr__(self, "marker", marker)
|
| 556 |
+
object.__setattr__(self, "requires_python", requires_python)
|
| 557 |
+
object.__setattr__(self, "dependencies", dependencies)
|
| 558 |
+
object.__setattr__(self, "vcs", vcs)
|
| 559 |
+
object.__setattr__(self, "directory", directory)
|
| 560 |
+
object.__setattr__(self, "archive", archive)
|
| 561 |
+
object.__setattr__(self, "index", index)
|
| 562 |
+
object.__setattr__(self, "sdist", sdist)
|
| 563 |
+
object.__setattr__(self, "wheels", wheels)
|
| 564 |
+
object.__setattr__(self, "attestation_identities", attestation_identities)
|
| 565 |
+
object.__setattr__(self, "tool", tool)
|
| 566 |
+
|
| 567 |
+
@classmethod
|
| 568 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self:
|
| 569 |
+
package = cls(
|
| 570 |
+
name=_get_required_as(d, str, _validate_normalized_name, "name"),
|
| 571 |
+
version=_get_as(d, str, Version, "version"),
|
| 572 |
+
requires_python=_get_as(d, str, SpecifierSet, "requires-python"),
|
| 573 |
+
dependencies=_get_sequence(d, Mapping, "dependencies"), # type: ignore[type-abstract]
|
| 574 |
+
marker=_get_as(d, str, Marker, "marker"),
|
| 575 |
+
vcs=_get_object(d, PackageVcs, "vcs"),
|
| 576 |
+
directory=_get_object(d, PackageDirectory, "directory"),
|
| 577 |
+
archive=_get_object(d, PackageArchive, "archive"),
|
| 578 |
+
index=_get(d, str, "index"),
|
| 579 |
+
sdist=_get_object(d, PackageSdist, "sdist"),
|
| 580 |
+
wheels=_get_sequence_of_objects(d, PackageWheel, "wheels"),
|
| 581 |
+
attestation_identities=_get_sequence(d, Mapping, "attestation-identities"), # type: ignore[type-abstract]
|
| 582 |
+
tool=_get(d, Mapping, "tool"), # type: ignore[type-abstract]
|
| 583 |
+
)
|
| 584 |
+
distributions = bool(package.sdist) + len(package.wheels or [])
|
| 585 |
+
direct_urls = (
|
| 586 |
+
bool(package.vcs) + bool(package.directory) + bool(package.archive)
|
| 587 |
+
)
|
| 588 |
+
if distributions > 0 and direct_urls > 0:
|
| 589 |
+
raise PylockValidationError(
|
| 590 |
+
"None of vcs, directory, archive must be set if sdist or wheels are set"
|
| 591 |
+
)
|
| 592 |
+
if distributions == 0 and direct_urls != 1:
|
| 593 |
+
raise PylockValidationError(
|
| 594 |
+
"Exactly one of vcs, directory, archive must be set "
|
| 595 |
+
"if sdist and wheels are not set"
|
| 596 |
+
)
|
| 597 |
+
for i, wheel in enumerate(package.wheels or []):
|
| 598 |
+
try:
|
| 599 |
+
(name, version, _, _) = parse_wheel_filename(wheel.filename)
|
| 600 |
+
except Exception as e:
|
| 601 |
+
raise PylockValidationError(
|
| 602 |
+
f"Invalid wheel filename {wheel.filename!r}",
|
| 603 |
+
context=f"wheels[{i}]",
|
| 604 |
+
) from e
|
| 605 |
+
if name != package.name:
|
| 606 |
+
raise PylockValidationError(
|
| 607 |
+
f"Name in {wheel.filename!r} is not consistent with "
|
| 608 |
+
f"package name {package.name!r}",
|
| 609 |
+
context=f"wheels[{i}]",
|
| 610 |
+
)
|
| 611 |
+
if package.version and version != package.version:
|
| 612 |
+
raise PylockValidationError(
|
| 613 |
+
f"Version in {wheel.filename!r} is not consistent with "
|
| 614 |
+
f"package version {str(package.version)!r}",
|
| 615 |
+
context=f"wheels[{i}]",
|
| 616 |
+
)
|
| 617 |
+
if package.sdist:
|
| 618 |
+
try:
|
| 619 |
+
name, version = parse_sdist_filename(package.sdist.filename)
|
| 620 |
+
except Exception as e:
|
| 621 |
+
raise PylockValidationError(
|
| 622 |
+
f"Invalid sdist filename {package.sdist.filename!r}",
|
| 623 |
+
context="sdist",
|
| 624 |
+
) from e
|
| 625 |
+
if name != package.name:
|
| 626 |
+
raise PylockValidationError(
|
| 627 |
+
f"Name in {package.sdist.filename!r} is not consistent with "
|
| 628 |
+
f"package name {package.name!r}",
|
| 629 |
+
context="sdist",
|
| 630 |
+
)
|
| 631 |
+
if package.version and version != package.version:
|
| 632 |
+
raise PylockValidationError(
|
| 633 |
+
f"Version in {package.sdist.filename!r} is not consistent with "
|
| 634 |
+
f"package version {str(package.version)!r}",
|
| 635 |
+
context="sdist",
|
| 636 |
+
)
|
| 637 |
+
try:
|
| 638 |
+
for i, attestation_identity in enumerate( # noqa: B007
|
| 639 |
+
package.attestation_identities or []
|
| 640 |
+
):
|
| 641 |
+
_get_required(attestation_identity, str, "kind")
|
| 642 |
+
except Exception as e:
|
| 643 |
+
raise PylockValidationError(
|
| 644 |
+
e, context=f"attestation-identities[{i}]"
|
| 645 |
+
) from e
|
| 646 |
+
return package
|
| 647 |
+
|
| 648 |
+
@property
|
| 649 |
+
def is_direct(self) -> bool:
|
| 650 |
+
return not (self.sdist or self.wheels)
|
| 651 |
+
|
| 652 |
+
|
| 653 |
+
@dataclass(frozen=True, init=False)
|
| 654 |
+
class Pylock:
|
| 655 |
+
"""A class representing a pylock file."""
|
| 656 |
+
|
| 657 |
+
lock_version: Version
|
| 658 |
+
environments: Sequence[Marker] | None = None
|
| 659 |
+
requires_python: SpecifierSet | None = None
|
| 660 |
+
extras: Sequence[NormalizedName] | None = None
|
| 661 |
+
dependency_groups: Sequence[str] | None = None
|
| 662 |
+
default_groups: Sequence[str] | None = None
|
| 663 |
+
created_by: str # type: ignore[misc]
|
| 664 |
+
packages: Sequence[Package] # type: ignore[misc]
|
| 665 |
+
tool: Mapping[str, Any] | None = None
|
| 666 |
+
|
| 667 |
+
def __init__(
|
| 668 |
+
self,
|
| 669 |
+
*,
|
| 670 |
+
lock_version: Version,
|
| 671 |
+
environments: Sequence[Marker] | None = None,
|
| 672 |
+
requires_python: SpecifierSet | None = None,
|
| 673 |
+
extras: Sequence[NormalizedName] | None = None,
|
| 674 |
+
dependency_groups: Sequence[str] | None = None,
|
| 675 |
+
default_groups: Sequence[str] | None = None,
|
| 676 |
+
created_by: str,
|
| 677 |
+
packages: Sequence[Package],
|
| 678 |
+
tool: Mapping[str, Any] | None = None,
|
| 679 |
+
) -> None:
|
| 680 |
+
# In Python 3.10+ make dataclass kw_only=True and remove __init__
|
| 681 |
+
object.__setattr__(self, "lock_version", lock_version)
|
| 682 |
+
object.__setattr__(self, "environments", environments)
|
| 683 |
+
object.__setattr__(self, "requires_python", requires_python)
|
| 684 |
+
object.__setattr__(self, "extras", extras)
|
| 685 |
+
object.__setattr__(self, "dependency_groups", dependency_groups)
|
| 686 |
+
object.__setattr__(self, "default_groups", default_groups)
|
| 687 |
+
object.__setattr__(self, "created_by", created_by)
|
| 688 |
+
object.__setattr__(self, "packages", packages)
|
| 689 |
+
object.__setattr__(self, "tool", tool)
|
| 690 |
+
|
| 691 |
+
@classmethod
|
| 692 |
+
def _from_dict(cls, d: Mapping[str, Any]) -> Self:
|
| 693 |
+
pylock = cls(
|
| 694 |
+
lock_version=_get_required_as(d, str, Version, "lock-version"),
|
| 695 |
+
environments=_get_sequence_as(d, str, Marker, "environments"),
|
| 696 |
+
extras=_get_sequence_as(d, str, _validate_normalized_name, "extras"),
|
| 697 |
+
dependency_groups=_get_sequence(d, str, "dependency-groups"),
|
| 698 |
+
default_groups=_get_sequence(d, str, "default-groups"),
|
| 699 |
+
created_by=_get_required(d, str, "created-by"),
|
| 700 |
+
requires_python=_get_as(d, str, SpecifierSet, "requires-python"),
|
| 701 |
+
packages=_get_required_sequence_of_objects(d, Package, "packages"),
|
| 702 |
+
tool=_get(d, Mapping, "tool"), # type: ignore[type-abstract]
|
| 703 |
+
)
|
| 704 |
+
if not Version("1") <= pylock.lock_version < Version("2"):
|
| 705 |
+
raise PylockUnsupportedVersionError(
|
| 706 |
+
f"pylock version {pylock.lock_version} is not supported"
|
| 707 |
+
)
|
| 708 |
+
if pylock.lock_version > Version("1.0"):
|
| 709 |
+
_logger.warning(
|
| 710 |
+
"pylock minor version %s is not supported", pylock.lock_version
|
| 711 |
+
)
|
| 712 |
+
return pylock
|
| 713 |
+
|
| 714 |
+
@classmethod
|
| 715 |
+
def from_dict(cls, d: Mapping[str, Any], /) -> Self:
|
| 716 |
+
"""Create and validate a Pylock instance from a TOML dictionary.
|
| 717 |
+
|
| 718 |
+
Raises :class:`PylockValidationError` if the input data is not
|
| 719 |
+
spec-compliant.
|
| 720 |
+
"""
|
| 721 |
+
return cls._from_dict(d)
|
| 722 |
+
|
| 723 |
+
def to_dict(self) -> Mapping[str, Any]:
|
| 724 |
+
"""Convert the Pylock instance to a TOML dictionary."""
|
| 725 |
+
return dataclasses.asdict(self, dict_factory=_toml_dict_factory)
|
| 726 |
+
|
| 727 |
+
def validate(self) -> None:
|
| 728 |
+
"""Validate the Pylock instance against the specification.
|
| 729 |
+
|
| 730 |
+
Raises :class:`PylockValidationError` otherwise."""
|
| 731 |
+
self.from_dict(self.to_dict())
|
| 732 |
+
|
| 733 |
+
def select(
|
| 734 |
+
self,
|
| 735 |
+
*,
|
| 736 |
+
environment: Environment | None = None,
|
| 737 |
+
tags: Sequence[Tag] | None = None,
|
| 738 |
+
extras: Collection[str] | None = None,
|
| 739 |
+
dependency_groups: Collection[str] | None = None,
|
| 740 |
+
) -> Iterator[
|
| 741 |
+
tuple[
|
| 742 |
+
Package,
|
| 743 |
+
PackageVcs
|
| 744 |
+
| PackageDirectory
|
| 745 |
+
| PackageArchive
|
| 746 |
+
| PackageWheel
|
| 747 |
+
| PackageSdist,
|
| 748 |
+
]
|
| 749 |
+
]:
|
| 750 |
+
"""Select what to install from the lock file.
|
| 751 |
+
|
| 752 |
+
The *environment* and *tags* parameters represent the environment being
|
| 753 |
+
selected for. If unspecified, ``packaging.markers.default_environment()`` and
|
| 754 |
+
``packaging.tags.sys_tags()`` are used.
|
| 755 |
+
|
| 756 |
+
The *extras* parameter represents the extras to install.
|
| 757 |
+
|
| 758 |
+
The *dependency_groups* parameter represents the groups to install. If
|
| 759 |
+
unspecified, the default groups are used.
|
| 760 |
+
|
| 761 |
+
This method must be used on valid Pylock instances (i.e. one obtained
|
| 762 |
+
from :meth:`Pylock.from_dict` or if constructed manually, after calling
|
| 763 |
+
:meth:`Pylock.validate`).
|
| 764 |
+
"""
|
| 765 |
+
compatible_tags_selector = create_compatible_tags_selector(tags or sys_tags())
|
| 766 |
+
|
| 767 |
+
# #. Gather the extras and dependency groups to install and set ``extras`` and
|
| 768 |
+
# ``dependency_groups`` for marker evaluation, respectively.
|
| 769 |
+
#
|
| 770 |
+
# #. ``extras`` SHOULD be set to the empty set by default.
|
| 771 |
+
# #. ``dependency_groups`` SHOULD be the set created from
|
| 772 |
+
# :ref:`pylock-default-groups` by default.
|
| 773 |
+
env = cast(
|
| 774 |
+
"dict[str, str | frozenset[str]]",
|
| 775 |
+
dict(
|
| 776 |
+
environment or {}, # Marker.evaluate will fill-up
|
| 777 |
+
extras=frozenset(extras or []),
|
| 778 |
+
dependency_groups=frozenset(
|
| 779 |
+
(self.default_groups or [])
|
| 780 |
+
if dependency_groups is None # to allow selecting no group
|
| 781 |
+
else dependency_groups
|
| 782 |
+
),
|
| 783 |
+
),
|
| 784 |
+
)
|
| 785 |
+
env_python_full_version = (
|
| 786 |
+
environment["python_full_version"]
|
| 787 |
+
if environment
|
| 788 |
+
else default_environment()["python_full_version"]
|
| 789 |
+
)
|
| 790 |
+
|
| 791 |
+
# #. Check if the metadata version specified by :ref:`pylock-lock-version` is
|
| 792 |
+
# supported; an error or warning MUST be raised as appropriate.
|
| 793 |
+
# Covered by lock.validate() which is a precondition for this method.
|
| 794 |
+
|
| 795 |
+
# #. If :ref:`pylock-requires-python` is specified, check that the environment
|
| 796 |
+
# being installed for meets the requirement; an error MUST be raised if it is
|
| 797 |
+
# not met.
|
| 798 |
+
if self.requires_python and not self.requires_python.contains(
|
| 799 |
+
env_python_full_version,
|
| 800 |
+
):
|
| 801 |
+
raise PylockSelectError(
|
| 802 |
+
f"python_full_version {env_python_full_version!r} "
|
| 803 |
+
f"in provided environment does not satisfy the Python version "
|
| 804 |
+
f"requirement {str(self.requires_python)!r}"
|
| 805 |
+
)
|
| 806 |
+
|
| 807 |
+
# #. If :ref:`pylock-environments` is specified, check that at least one of the
|
| 808 |
+
# environment marker expressions is satisfied; an error MUST be raised if no
|
| 809 |
+
# expression is satisfied.
|
| 810 |
+
if self.environments:
|
| 811 |
+
for env_marker in self.environments:
|
| 812 |
+
if env_marker.evaluate(
|
| 813 |
+
cast("dict[str, str]", environment or {}), context="requirement"
|
| 814 |
+
):
|
| 815 |
+
break
|
| 816 |
+
else:
|
| 817 |
+
raise PylockSelectError(
|
| 818 |
+
"Provided environment does not satisfy any of the "
|
| 819 |
+
"environments specified in the lock file"
|
| 820 |
+
)
|
| 821 |
+
|
| 822 |
+
# #. For each package listed in :ref:`pylock-packages`:
|
| 823 |
+
selected_packages_by_name: dict[str, tuple[int, Package]] = {}
|
| 824 |
+
for package_index, package in enumerate(self.packages):
|
| 825 |
+
# #. If :ref:`pylock-packages-marker` is specified, check if it is
|
| 826 |
+
# satisfied;if it isn't, skip to the next package.
|
| 827 |
+
if package.marker and not package.marker.evaluate(env, context="lock_file"):
|
| 828 |
+
continue
|
| 829 |
+
|
| 830 |
+
# #. If :ref:`pylock-packages-requires-python` is specified, check if it is
|
| 831 |
+
# satisfied; an error MUST be raised if it isn't.
|
| 832 |
+
if package.requires_python and not package.requires_python.contains(
|
| 833 |
+
env_python_full_version,
|
| 834 |
+
):
|
| 835 |
+
raise PylockSelectError(
|
| 836 |
+
f"python_full_version {env_python_full_version!r} "
|
| 837 |
+
f"in provided environment does not satisfy the Python version "
|
| 838 |
+
f"requirement {str(package.requires_python)!r} for package "
|
| 839 |
+
f"{package.name!r} at packages[{package_index}]"
|
| 840 |
+
)
|
| 841 |
+
|
| 842 |
+
# #. Check that no other conflicting instance of the package has been slated
|
| 843 |
+
# to be installed; an error about the ambiguity MUST be raised otherwise.
|
| 844 |
+
if package.name in selected_packages_by_name:
|
| 845 |
+
raise PylockSelectError(
|
| 846 |
+
f"Multiple packages with the name {package.name!r} are "
|
| 847 |
+
f"selected at packages[{package_index}] and "
|
| 848 |
+
f"packages[{selected_packages_by_name[package.name][0]}]"
|
| 849 |
+
)
|
| 850 |
+
|
| 851 |
+
# #. Check that the source of the package is specified appropriately (i.e.
|
| 852 |
+
# there are no conflicting sources in the package entry);
|
| 853 |
+
# an error MUST be raised if any issues are found.
|
| 854 |
+
# Covered by lock.validate() which is a precondition for this method.
|
| 855 |
+
|
| 856 |
+
# #. Add the package to the set of packages to install.
|
| 857 |
+
selected_packages_by_name[package.name] = (package_index, package)
|
| 858 |
+
|
| 859 |
+
# #. For each package to be installed:
|
| 860 |
+
for package_index, package in selected_packages_by_name.values():
|
| 861 |
+
# - If :ref:`pylock-packages-vcs` is set:
|
| 862 |
+
if package.vcs is not None:
|
| 863 |
+
yield package, package.vcs
|
| 864 |
+
|
| 865 |
+
# - Else if :ref:`pylock-packages-directory` is set:
|
| 866 |
+
elif package.directory is not None:
|
| 867 |
+
yield package, package.directory
|
| 868 |
+
|
| 869 |
+
# - Else if :ref:`pylock-packages-archive` is set:
|
| 870 |
+
elif package.archive is not None:
|
| 871 |
+
yield package, package.archive
|
| 872 |
+
|
| 873 |
+
# - Else if there are entries for :ref:`pylock-packages-wheels`:
|
| 874 |
+
elif package.wheels:
|
| 875 |
+
# #. Look for the appropriate wheel file based on
|
| 876 |
+
# :ref:`pylock-packages-wheels-name`; if one is not found then move
|
| 877 |
+
# on to :ref:`pylock-packages-sdist` or an error MUST be raised about
|
| 878 |
+
# a lack of source for the project.
|
| 879 |
+
best_wheel = next(
|
| 880 |
+
compatible_tags_selector(
|
| 881 |
+
(wheel, parse_wheel_filename(wheel.filename)[-1])
|
| 882 |
+
for wheel in package.wheels
|
| 883 |
+
),
|
| 884 |
+
None,
|
| 885 |
+
)
|
| 886 |
+
if best_wheel:
|
| 887 |
+
yield package, best_wheel
|
| 888 |
+
elif package.sdist is not None:
|
| 889 |
+
yield package, package.sdist
|
| 890 |
+
else:
|
| 891 |
+
raise PylockSelectError(
|
| 892 |
+
f"No wheel found matching the provided tags "
|
| 893 |
+
f"for package {package.name!r} "
|
| 894 |
+
f"at packages[{package_index}], "
|
| 895 |
+
f"and no sdist available as a fallback"
|
| 896 |
+
)
|
| 897 |
+
|
| 898 |
+
# - Else if no :ref:`pylock-packages-wheels` file is found or
|
| 899 |
+
# :ref:`pylock-packages-sdist` is solely set:
|
| 900 |
+
elif package.sdist is not None:
|
| 901 |
+
yield package, package.sdist
|
| 902 |
+
|
| 903 |
+
else:
|
| 904 |
+
# Covered by lock.validate() which is a precondition for this method.
|
| 905 |
+
raise NotImplementedError # pragma: no cover
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/requirements.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
from typing import Iterator
|
| 7 |
+
|
| 8 |
+
from ._parser import parse_requirement as _parse_requirement
|
| 9 |
+
from ._tokenizer import ParserSyntaxError
|
| 10 |
+
from .markers import Marker, _normalize_extra_values
|
| 11 |
+
from .specifiers import SpecifierSet
|
| 12 |
+
from .utils import canonicalize_name
|
| 13 |
+
|
| 14 |
+
__all__ = [
|
| 15 |
+
"InvalidRequirement",
|
| 16 |
+
"Requirement",
|
| 17 |
+
]
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def __dir__() -> list[str]:
|
| 21 |
+
return __all__
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class InvalidRequirement(ValueError):
|
| 25 |
+
"""
|
| 26 |
+
An invalid requirement was found, users should refer to PEP 508.
|
| 27 |
+
"""
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class Requirement:
|
| 31 |
+
"""Parse a requirement.
|
| 32 |
+
|
| 33 |
+
Parse a given requirement string into its parts, such as name, specifier,
|
| 34 |
+
URL, and extras. Raises InvalidRequirement on a badly-formed requirement
|
| 35 |
+
string.
|
| 36 |
+
|
| 37 |
+
Instances are safe to serialize with :mod:`pickle`. They use a stable
|
| 38 |
+
format so the same pickle can be loaded in future packaging releases.
|
| 39 |
+
|
| 40 |
+
.. versionchanged:: 26.2
|
| 41 |
+
|
| 42 |
+
Added a stable pickle format. Pickles created with packaging 26.2+ can
|
| 43 |
+
be unpickled with future releases. Backward compatibility with pickles
|
| 44 |
+
from pip._vendor.packaging < 26.2 is supported but may be removed in a future
|
| 45 |
+
release.
|
| 46 |
+
"""
|
| 47 |
+
|
| 48 |
+
# TODO: Can we test whether something is contained within a requirement?
|
| 49 |
+
# If so how do we do that? Do we need to test against the _name_ of
|
| 50 |
+
# the thing as well as the version? What about the markers?
|
| 51 |
+
# TODO: Can we normalize the name and extra name?
|
| 52 |
+
|
| 53 |
+
def __init__(self, requirement_string: str) -> None:
|
| 54 |
+
try:
|
| 55 |
+
parsed = _parse_requirement(requirement_string)
|
| 56 |
+
except ParserSyntaxError as e:
|
| 57 |
+
raise InvalidRequirement(str(e)) from e
|
| 58 |
+
|
| 59 |
+
self.name: str = parsed.name
|
| 60 |
+
self.url: str | None = parsed.url or None
|
| 61 |
+
self.extras: set[str] = set(parsed.extras or [])
|
| 62 |
+
self.specifier: SpecifierSet = SpecifierSet(parsed.specifier)
|
| 63 |
+
self.marker: Marker | None = None
|
| 64 |
+
if parsed.marker is not None:
|
| 65 |
+
self.marker = Marker.__new__(Marker)
|
| 66 |
+
self.marker._markers = _normalize_extra_values(parsed.marker)
|
| 67 |
+
|
| 68 |
+
def _iter_parts(self, name: str) -> Iterator[str]:
|
| 69 |
+
yield name
|
| 70 |
+
|
| 71 |
+
if self.extras:
|
| 72 |
+
formatted_extras = ",".join(sorted(self.extras))
|
| 73 |
+
yield f"[{formatted_extras}]"
|
| 74 |
+
|
| 75 |
+
if self.specifier:
|
| 76 |
+
yield str(self.specifier)
|
| 77 |
+
|
| 78 |
+
if self.url:
|
| 79 |
+
yield f" @ {self.url}"
|
| 80 |
+
if self.marker:
|
| 81 |
+
yield " "
|
| 82 |
+
|
| 83 |
+
if self.marker:
|
| 84 |
+
yield f"; {self.marker}"
|
| 85 |
+
|
| 86 |
+
def __getstate__(self) -> str:
|
| 87 |
+
# Return the requirement string for compactness and stability.
|
| 88 |
+
# Re-parsed on load to reconstruct all fields.
|
| 89 |
+
return str(self)
|
| 90 |
+
|
| 91 |
+
def __setstate__(self, state: object) -> None:
|
| 92 |
+
if isinstance(state, str):
|
| 93 |
+
# New format (26.2+): just the requirement string.
|
| 94 |
+
try:
|
| 95 |
+
tmp = Requirement(state)
|
| 96 |
+
except InvalidRequirement as exc:
|
| 97 |
+
raise TypeError(f"Cannot restore Requirement from {state!r}") from exc
|
| 98 |
+
self.name = tmp.name
|
| 99 |
+
self.url = tmp.url
|
| 100 |
+
self.extras = tmp.extras
|
| 101 |
+
self.specifier = tmp.specifier
|
| 102 |
+
self.marker = tmp.marker
|
| 103 |
+
return
|
| 104 |
+
if isinstance(state, dict):
|
| 105 |
+
# Old format (packaging <= 26.1, no __slots__): plain __dict__.
|
| 106 |
+
self.__dict__.update(state)
|
| 107 |
+
return
|
| 108 |
+
raise TypeError(f"Cannot restore Requirement from {state!r}")
|
| 109 |
+
|
| 110 |
+
def __str__(self) -> str:
|
| 111 |
+
return "".join(self._iter_parts(self.name))
|
| 112 |
+
|
| 113 |
+
def __repr__(self) -> str:
|
| 114 |
+
return f"<{self.__class__.__name__}({str(self)!r})>"
|
| 115 |
+
|
| 116 |
+
def __hash__(self) -> int:
|
| 117 |
+
return hash(tuple(self._iter_parts(canonicalize_name(self.name))))
|
| 118 |
+
|
| 119 |
+
def __eq__(self, other: object) -> bool:
|
| 120 |
+
if not isinstance(other, Requirement):
|
| 121 |
+
return NotImplemented
|
| 122 |
+
|
| 123 |
+
return (
|
| 124 |
+
canonicalize_name(self.name) == canonicalize_name(other.name)
|
| 125 |
+
and self.extras == other.extras
|
| 126 |
+
and self.specifier == other.specifier
|
| 127 |
+
and self.url == other.url
|
| 128 |
+
and self.marker == other.marker
|
| 129 |
+
)
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/specifiers.py
ADDED
|
@@ -0,0 +1,1943 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
"""
|
| 5 |
+
.. testsetup::
|
| 6 |
+
|
| 7 |
+
from pip._vendor.packaging.specifiers import Specifier, SpecifierSet, InvalidSpecifier
|
| 8 |
+
from pip._vendor.packaging.version import Version
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
from __future__ import annotations
|
| 12 |
+
|
| 13 |
+
import abc
|
| 14 |
+
import enum
|
| 15 |
+
import functools
|
| 16 |
+
import itertools
|
| 17 |
+
import re
|
| 18 |
+
import sys
|
| 19 |
+
import typing
|
| 20 |
+
from typing import (
|
| 21 |
+
TYPE_CHECKING,
|
| 22 |
+
Any,
|
| 23 |
+
Callable,
|
| 24 |
+
Final,
|
| 25 |
+
Iterable,
|
| 26 |
+
Iterator,
|
| 27 |
+
Sequence,
|
| 28 |
+
TypeVar,
|
| 29 |
+
Union,
|
| 30 |
+
)
|
| 31 |
+
|
| 32 |
+
from .utils import canonicalize_version
|
| 33 |
+
from .version import InvalidVersion, Version
|
| 34 |
+
|
| 35 |
+
if sys.version_info >= (3, 10):
|
| 36 |
+
from typing import TypeGuard # pragma: no cover
|
| 37 |
+
elif TYPE_CHECKING:
|
| 38 |
+
from typing_extensions import TypeGuard
|
| 39 |
+
|
| 40 |
+
__all__ = [
|
| 41 |
+
"BaseSpecifier",
|
| 42 |
+
"InvalidSpecifier",
|
| 43 |
+
"Specifier",
|
| 44 |
+
"SpecifierSet",
|
| 45 |
+
]
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def __dir__() -> list[str]:
|
| 49 |
+
return __all__
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _validate_spec(spec: object, /) -> TypeGuard[tuple[str, str]]:
|
| 53 |
+
return (
|
| 54 |
+
isinstance(spec, tuple)
|
| 55 |
+
and len(spec) == 2
|
| 56 |
+
and isinstance(spec[0], str)
|
| 57 |
+
and isinstance(spec[1], str)
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def _validate_pre(pre: object, /) -> TypeGuard[bool | None]:
|
| 62 |
+
return pre is None or isinstance(pre, bool)
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
T = TypeVar("T")
|
| 66 |
+
UnparsedVersion = Union[Version, str]
|
| 67 |
+
UnparsedVersionVar = TypeVar("UnparsedVersionVar", bound=UnparsedVersion)
|
| 68 |
+
CallableOperator = Callable[[Version, str], bool]
|
| 69 |
+
|
| 70 |
+
# The smallest possible PEP 440 version. No valid version is less than this.
|
| 71 |
+
_MIN_VERSION: Final[Version] = Version("0.dev0")
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def _trim_release(release: tuple[int, ...]) -> tuple[int, ...]:
|
| 75 |
+
"""Strip trailing zeros from a release tuple for normalized comparison."""
|
| 76 |
+
end = len(release)
|
| 77 |
+
while end > 1 and release[end - 1] == 0:
|
| 78 |
+
end -= 1
|
| 79 |
+
return release if end == len(release) else release[:end]
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
class _BoundaryKind(enum.Enum):
|
| 83 |
+
"""Where a boundary marker sits in the version ordering."""
|
| 84 |
+
|
| 85 |
+
AFTER_LOCALS = enum.auto() # after V+local, before V.post0
|
| 86 |
+
AFTER_POSTS = enum.auto() # after V.postN, before next release
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
@functools.total_ordering
|
| 90 |
+
class _BoundaryVersion:
|
| 91 |
+
"""A point on the version line between two real PEP 440 versions.
|
| 92 |
+
|
| 93 |
+
Some specifier semantics imply boundaries between real versions:
|
| 94 |
+
``<=1.0`` includes ``1.0+local`` and ``>1.0`` excludes
|
| 95 |
+
``1.0.post0``. No real :class:`Version` falls on those boundaries,
|
| 96 |
+
so this class creates values that sort between the real versions
|
| 97 |
+
on either side.
|
| 98 |
+
|
| 99 |
+
Two kinds exist, shown relative to a base version V::
|
| 100 |
+
|
| 101 |
+
V < V+local < AFTER_LOCALS(V) < V.post0 < AFTER_POSTS(V)
|
| 102 |
+
|
| 103 |
+
``AFTER_LOCALS`` sits after V and every V+local, but before
|
| 104 |
+
V.post0. Upper bound of ``<=V``, ``==V``, ``!=V``.
|
| 105 |
+
|
| 106 |
+
``AFTER_POSTS`` sits after every V.postN, but before the next
|
| 107 |
+
release segment. Lower bound of ``>V`` (final or pre-release V)
|
| 108 |
+
to exclude post-releases per PEP 440.
|
| 109 |
+
"""
|
| 110 |
+
|
| 111 |
+
__slots__ = ("_kind", "_trimmed_release", "version")
|
| 112 |
+
|
| 113 |
+
def __init__(self, version: Version, kind: _BoundaryKind) -> None:
|
| 114 |
+
self.version = version
|
| 115 |
+
self._kind = kind
|
| 116 |
+
self._trimmed_release = _trim_release(version.release)
|
| 117 |
+
|
| 118 |
+
def _is_family(self, other: Version) -> bool:
|
| 119 |
+
"""Is ``other`` a version that this boundary sorts above?"""
|
| 120 |
+
v = self.version
|
| 121 |
+
if not (
|
| 122 |
+
other.epoch == v.epoch
|
| 123 |
+
and _trim_release(other.release) == self._trimmed_release
|
| 124 |
+
and other.pre == v.pre
|
| 125 |
+
):
|
| 126 |
+
return False
|
| 127 |
+
if self._kind == _BoundaryKind.AFTER_LOCALS:
|
| 128 |
+
# Local family: exact same public version (any local label).
|
| 129 |
+
return other.post == v.post and other.dev == v.dev
|
| 130 |
+
# Post family: same base + any post-release (or identical).
|
| 131 |
+
return other.dev == v.dev or other.post is not None
|
| 132 |
+
|
| 133 |
+
def __eq__(self, other: object) -> bool:
|
| 134 |
+
if isinstance(other, _BoundaryVersion):
|
| 135 |
+
return self.version == other.version and self._kind == other._kind
|
| 136 |
+
return NotImplemented
|
| 137 |
+
|
| 138 |
+
def __lt__(self, other: _BoundaryVersion | Version) -> bool:
|
| 139 |
+
if isinstance(other, _BoundaryVersion):
|
| 140 |
+
if self.version != other.version:
|
| 141 |
+
return self.version < other.version
|
| 142 |
+
return self._kind.value < other._kind.value
|
| 143 |
+
return not self._is_family(other) and self.version < other
|
| 144 |
+
|
| 145 |
+
def __hash__(self) -> int:
|
| 146 |
+
return hash((self.version, self._kind))
|
| 147 |
+
|
| 148 |
+
def __repr__(self) -> str:
|
| 149 |
+
return f"{self.__class__.__name__}({self.version!r}, {self._kind.name})"
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
@functools.total_ordering
|
| 153 |
+
class _LowerBound:
|
| 154 |
+
"""Lower bound of a version range.
|
| 155 |
+
|
| 156 |
+
A version *v* of ``None`` means unbounded below (-inf).
|
| 157 |
+
At equal versions, ``[v`` sorts before ``(v`` because an inclusive
|
| 158 |
+
bound starts earlier.
|
| 159 |
+
"""
|
| 160 |
+
|
| 161 |
+
__slots__ = ("inclusive", "version")
|
| 162 |
+
|
| 163 |
+
def __init__(self, version: _VersionOrBoundary, inclusive: bool) -> None:
|
| 164 |
+
self.version = version
|
| 165 |
+
self.inclusive = inclusive
|
| 166 |
+
|
| 167 |
+
def __eq__(self, other: object) -> bool:
|
| 168 |
+
if not isinstance(other, _LowerBound):
|
| 169 |
+
return NotImplemented # pragma: no cover
|
| 170 |
+
return self.version == other.version and self.inclusive == other.inclusive
|
| 171 |
+
|
| 172 |
+
def __lt__(self, other: _LowerBound) -> bool:
|
| 173 |
+
if not isinstance(other, _LowerBound): # pragma: no cover
|
| 174 |
+
return NotImplemented
|
| 175 |
+
# -inf < anything (except -inf).
|
| 176 |
+
if self.version is None:
|
| 177 |
+
return other.version is not None
|
| 178 |
+
if other.version is None:
|
| 179 |
+
return False
|
| 180 |
+
if self.version != other.version:
|
| 181 |
+
return self.version < other.version
|
| 182 |
+
# [v < (v: inclusive starts earlier.
|
| 183 |
+
return self.inclusive and not other.inclusive
|
| 184 |
+
|
| 185 |
+
def __hash__(self) -> int:
|
| 186 |
+
return hash((self.version, self.inclusive))
|
| 187 |
+
|
| 188 |
+
def __repr__(self) -> str:
|
| 189 |
+
bracket = "[" if self.inclusive else "("
|
| 190 |
+
return f"<{self.__class__.__name__} {bracket}{self.version!r}>"
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
@functools.total_ordering
|
| 194 |
+
class _UpperBound:
|
| 195 |
+
"""Upper bound of a version range.
|
| 196 |
+
|
| 197 |
+
A version *v* of ``None`` means unbounded above (+inf).
|
| 198 |
+
At equal versions, ``v)`` sorts before ``v]`` because an exclusive
|
| 199 |
+
bound ends earlier.
|
| 200 |
+
"""
|
| 201 |
+
|
| 202 |
+
__slots__ = ("inclusive", "version")
|
| 203 |
+
|
| 204 |
+
def __init__(self, version: _VersionOrBoundary, inclusive: bool) -> None:
|
| 205 |
+
self.version = version
|
| 206 |
+
self.inclusive = inclusive
|
| 207 |
+
|
| 208 |
+
def __eq__(self, other: object) -> bool:
|
| 209 |
+
if not isinstance(other, _UpperBound):
|
| 210 |
+
return NotImplemented # pragma: no cover
|
| 211 |
+
return self.version == other.version and self.inclusive == other.inclusive
|
| 212 |
+
|
| 213 |
+
def __lt__(self, other: _UpperBound) -> bool:
|
| 214 |
+
if not isinstance(other, _UpperBound): # pragma: no cover
|
| 215 |
+
return NotImplemented
|
| 216 |
+
# Nothing < +inf (except +inf itself).
|
| 217 |
+
if self.version is None:
|
| 218 |
+
return False
|
| 219 |
+
if other.version is None:
|
| 220 |
+
return True
|
| 221 |
+
if self.version != other.version:
|
| 222 |
+
return self.version < other.version
|
| 223 |
+
# v) < v]: exclusive ends earlier.
|
| 224 |
+
return not self.inclusive and other.inclusive
|
| 225 |
+
|
| 226 |
+
def __hash__(self) -> int:
|
| 227 |
+
return hash((self.version, self.inclusive))
|
| 228 |
+
|
| 229 |
+
def __repr__(self) -> str:
|
| 230 |
+
bracket = "]" if self.inclusive else ")"
|
| 231 |
+
return f"<{self.__class__.__name__} {self.version!r}{bracket}>"
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
if typing.TYPE_CHECKING:
|
| 235 |
+
_VersionOrBoundary = Union[Version, _BoundaryVersion, None]
|
| 236 |
+
|
| 237 |
+
#: A single contiguous version range, represented as a
|
| 238 |
+
#: (lower bound, upper bound) pair.
|
| 239 |
+
_VersionRange = tuple[_LowerBound, _UpperBound]
|
| 240 |
+
|
| 241 |
+
_NEG_INF = _LowerBound(None, False)
|
| 242 |
+
_POS_INF = _UpperBound(None, False)
|
| 243 |
+
_FULL_RANGE: tuple[_VersionRange] = ((_NEG_INF, _POS_INF),)
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
def _range_is_empty(lower: _LowerBound, upper: _UpperBound) -> bool:
|
| 247 |
+
"""True when the range defined by *lower* and *upper* contains no versions."""
|
| 248 |
+
if lower.version is None or upper.version is None:
|
| 249 |
+
return False
|
| 250 |
+
if lower.version == upper.version:
|
| 251 |
+
return not (lower.inclusive and upper.inclusive)
|
| 252 |
+
return lower.version > upper.version
|
| 253 |
+
|
| 254 |
+
|
| 255 |
+
def _intersect_ranges(
|
| 256 |
+
left: Sequence[_VersionRange],
|
| 257 |
+
right: Sequence[_VersionRange],
|
| 258 |
+
) -> list[_VersionRange]:
|
| 259 |
+
"""Intersect two sorted, non-overlapping range lists (two-pointer merge)."""
|
| 260 |
+
result: list[_VersionRange] = []
|
| 261 |
+
left_index = right_index = 0
|
| 262 |
+
while left_index < len(left) and right_index < len(right):
|
| 263 |
+
left_lower, left_upper = left[left_index]
|
| 264 |
+
right_lower, right_upper = right[right_index]
|
| 265 |
+
|
| 266 |
+
lower = max(left_lower, right_lower)
|
| 267 |
+
upper = min(left_upper, right_upper)
|
| 268 |
+
|
| 269 |
+
if not _range_is_empty(lower, upper):
|
| 270 |
+
result.append((lower, upper))
|
| 271 |
+
|
| 272 |
+
# Advance whichever side has the smaller upper bound.
|
| 273 |
+
if left_upper < right_upper:
|
| 274 |
+
left_index += 1
|
| 275 |
+
else:
|
| 276 |
+
right_index += 1
|
| 277 |
+
|
| 278 |
+
return result
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
def _next_prefix_dev0(version: Version) -> Version:
|
| 282 |
+
"""Smallest version in the next prefix: 1.2 -> 1.3.dev0."""
|
| 283 |
+
release = (*version.release[:-1], version.release[-1] + 1)
|
| 284 |
+
return Version.from_parts(epoch=version.epoch, release=release, dev=0)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
def _base_dev0(version: Version) -> Version:
|
| 288 |
+
"""The .dev0 of a version's base release: 1.2 -> 1.2.dev0."""
|
| 289 |
+
return Version.from_parts(epoch=version.epoch, release=version.release, dev=0)
|
| 290 |
+
|
| 291 |
+
|
| 292 |
+
def _coerce_version(version: UnparsedVersion) -> Version | None:
|
| 293 |
+
if not isinstance(version, Version):
|
| 294 |
+
try:
|
| 295 |
+
version = Version(version)
|
| 296 |
+
except InvalidVersion:
|
| 297 |
+
return None
|
| 298 |
+
return version
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
def _public_version(version: Version) -> Version:
|
| 302 |
+
if version.local is None:
|
| 303 |
+
return version
|
| 304 |
+
return version.__replace__(local=None)
|
| 305 |
+
|
| 306 |
+
|
| 307 |
+
def _post_base(version: Version) -> Version:
|
| 308 |
+
"""The version that *version* is a post-release of.
|
| 309 |
+
|
| 310 |
+
1.0.post1 -> 1.0, 1.0a1.post0 -> 1.0a1, 1.0.post0.dev1 -> 1.0.
|
| 311 |
+
"""
|
| 312 |
+
return version.__replace__(post=None, dev=None, local=None)
|
| 313 |
+
|
| 314 |
+
|
| 315 |
+
def _earliest_prerelease(version: Version) -> Version:
|
| 316 |
+
"""Earliest pre-release of *version*.
|
| 317 |
+
|
| 318 |
+
1.2 -> 1.2.dev0, 1.2.post1 -> 1.2.post1.dev0.
|
| 319 |
+
"""
|
| 320 |
+
return version.__replace__(dev=0, local=None)
|
| 321 |
+
|
| 322 |
+
|
| 323 |
+
def _nearest_non_prerelease(
|
| 324 |
+
v: _VersionOrBoundary,
|
| 325 |
+
) -> Version | None:
|
| 326 |
+
"""Smallest non-pre-release version at or above *v*, or None."""
|
| 327 |
+
if v is None:
|
| 328 |
+
return None
|
| 329 |
+
if isinstance(v, _BoundaryVersion):
|
| 330 |
+
inner = v.version
|
| 331 |
+
if inner.is_prerelease:
|
| 332 |
+
# AFTER_LOCALS(1.0a1) -> nearest non-pre is 1.0
|
| 333 |
+
return inner.__replace__(pre=None, dev=None, local=None)
|
| 334 |
+
# AFTER_LOCALS(1.0) -> nearest non-pre is 1.0.post0
|
| 335 |
+
# AFTER_LOCALS(1.0.post0) -> nearest non-pre is 1.0.post1
|
| 336 |
+
k = (inner.post + 1) if inner.post is not None else 0
|
| 337 |
+
return inner.__replace__(post=k, local=None)
|
| 338 |
+
if not v.is_prerelease:
|
| 339 |
+
return v
|
| 340 |
+
# Strip pre/dev to get the final or post-release form.
|
| 341 |
+
return v.__replace__(pre=None, dev=None, local=None)
|
| 342 |
+
|
| 343 |
+
|
| 344 |
+
class InvalidSpecifier(ValueError):
|
| 345 |
+
"""
|
| 346 |
+
Raised when attempting to create a :class:`Specifier` with a specifier
|
| 347 |
+
string that is invalid.
|
| 348 |
+
|
| 349 |
+
>>> Specifier("lolwat")
|
| 350 |
+
Traceback (most recent call last):
|
| 351 |
+
...
|
| 352 |
+
packaging.specifiers.InvalidSpecifier: Invalid specifier: 'lolwat'
|
| 353 |
+
"""
|
| 354 |
+
|
| 355 |
+
|
| 356 |
+
class BaseSpecifier(metaclass=abc.ABCMeta):
|
| 357 |
+
__slots__ = ()
|
| 358 |
+
__match_args__ = ("_str",)
|
| 359 |
+
|
| 360 |
+
@property
|
| 361 |
+
def _str(self) -> str:
|
| 362 |
+
"""Internal property for match_args"""
|
| 363 |
+
return str(self)
|
| 364 |
+
|
| 365 |
+
@abc.abstractmethod
|
| 366 |
+
def __str__(self) -> str:
|
| 367 |
+
"""
|
| 368 |
+
Returns the str representation of this Specifier-like object. This
|
| 369 |
+
should be representative of the Specifier itself.
|
| 370 |
+
"""
|
| 371 |
+
|
| 372 |
+
@abc.abstractmethod
|
| 373 |
+
def __hash__(self) -> int:
|
| 374 |
+
"""
|
| 375 |
+
Returns a hash value for this Specifier-like object.
|
| 376 |
+
"""
|
| 377 |
+
|
| 378 |
+
@abc.abstractmethod
|
| 379 |
+
def __eq__(self, other: object) -> bool:
|
| 380 |
+
"""
|
| 381 |
+
Returns a boolean representing whether or not the two Specifier-like
|
| 382 |
+
objects are equal.
|
| 383 |
+
|
| 384 |
+
:param other: The other object to check against.
|
| 385 |
+
"""
|
| 386 |
+
|
| 387 |
+
@property
|
| 388 |
+
@abc.abstractmethod
|
| 389 |
+
def prereleases(self) -> bool | None:
|
| 390 |
+
"""Whether or not pre-releases as a whole are allowed.
|
| 391 |
+
|
| 392 |
+
This can be set to either ``True`` or ``False`` to explicitly enable or disable
|
| 393 |
+
prereleases or it can be set to ``None`` (the default) to use default semantics.
|
| 394 |
+
"""
|
| 395 |
+
|
| 396 |
+
@prereleases.setter # noqa: B027
|
| 397 |
+
def prereleases(self, value: bool) -> None:
|
| 398 |
+
"""Setter for :attr:`prereleases`.
|
| 399 |
+
|
| 400 |
+
:param value: The value to set.
|
| 401 |
+
"""
|
| 402 |
+
|
| 403 |
+
@abc.abstractmethod
|
| 404 |
+
def contains(self, item: str, prereleases: bool | None = None) -> bool:
|
| 405 |
+
"""
|
| 406 |
+
Determines if the given item is contained within this specifier.
|
| 407 |
+
"""
|
| 408 |
+
|
| 409 |
+
@typing.overload
|
| 410 |
+
def filter(
|
| 411 |
+
self,
|
| 412 |
+
iterable: Iterable[UnparsedVersionVar],
|
| 413 |
+
prereleases: bool | None = None,
|
| 414 |
+
key: None = ...,
|
| 415 |
+
) -> Iterator[UnparsedVersionVar]: ...
|
| 416 |
+
|
| 417 |
+
@typing.overload
|
| 418 |
+
def filter(
|
| 419 |
+
self,
|
| 420 |
+
iterable: Iterable[T],
|
| 421 |
+
prereleases: bool | None = None,
|
| 422 |
+
key: Callable[[T], UnparsedVersion] = ...,
|
| 423 |
+
) -> Iterator[T]: ...
|
| 424 |
+
|
| 425 |
+
@abc.abstractmethod
|
| 426 |
+
def filter(
|
| 427 |
+
self,
|
| 428 |
+
iterable: Iterable[Any],
|
| 429 |
+
prereleases: bool | None = None,
|
| 430 |
+
key: Callable[[Any], UnparsedVersion] | None = None,
|
| 431 |
+
) -> Iterator[Any]:
|
| 432 |
+
"""
|
| 433 |
+
Takes an iterable of items and filters them so that only items which
|
| 434 |
+
are contained within this specifier are allowed in it.
|
| 435 |
+
"""
|
| 436 |
+
|
| 437 |
+
|
| 438 |
+
class Specifier(BaseSpecifier):
|
| 439 |
+
"""This class abstracts handling of version specifiers.
|
| 440 |
+
|
| 441 |
+
.. tip::
|
| 442 |
+
|
| 443 |
+
It is generally not required to instantiate this manually. You should instead
|
| 444 |
+
prefer to work with :class:`SpecifierSet` instead, which can parse
|
| 445 |
+
comma-separated version specifiers (which is what package metadata contains).
|
| 446 |
+
|
| 447 |
+
Instances are safe to serialize with :mod:`pickle`. They use a stable
|
| 448 |
+
format so the same pickle can be loaded in future packaging releases.
|
| 449 |
+
|
| 450 |
+
.. versionchanged:: 26.2
|
| 451 |
+
|
| 452 |
+
Added a stable pickle format. Pickles created with packaging 26.2+ can
|
| 453 |
+
be unpickled with future releases. Backward compatibility with pickles
|
| 454 |
+
from pip._vendor.packaging < 26.2 is supported but may be removed in a future
|
| 455 |
+
release.
|
| 456 |
+
"""
|
| 457 |
+
|
| 458 |
+
__slots__ = (
|
| 459 |
+
"_prereleases",
|
| 460 |
+
"_ranges",
|
| 461 |
+
"_spec",
|
| 462 |
+
"_spec_version",
|
| 463 |
+
"_wildcard_split",
|
| 464 |
+
)
|
| 465 |
+
|
| 466 |
+
_specifier_regex_str = r"""
|
| 467 |
+
(?:
|
| 468 |
+
(?:
|
| 469 |
+
# The identity operators allow for an escape hatch that will
|
| 470 |
+
# do an exact string match of the version you wish to install.
|
| 471 |
+
# This will not be parsed by PEP 440 and we cannot determine
|
| 472 |
+
# any semantic meaning from it. This operator is discouraged
|
| 473 |
+
# but included entirely as an escape hatch.
|
| 474 |
+
=== # Only match for the identity operator
|
| 475 |
+
\s*
|
| 476 |
+
[^\s;)]* # The arbitrary version can be just about anything,
|
| 477 |
+
# we match everything except for whitespace, a
|
| 478 |
+
# semi-colon for marker support, and a closing paren
|
| 479 |
+
# since versions can be enclosed in them.
|
| 480 |
+
)
|
| 481 |
+
|
|
| 482 |
+
(?:
|
| 483 |
+
# The (non)equality operators allow for wild card and local
|
| 484 |
+
# versions to be specified so we have to define these two
|
| 485 |
+
# operators separately to enable that.
|
| 486 |
+
(?:==|!=) # Only match for equals and not equals
|
| 487 |
+
|
| 488 |
+
\s*
|
| 489 |
+
v?
|
| 490 |
+
(?:[0-9]+!)? # epoch
|
| 491 |
+
[0-9]+(?:\.[0-9]+)* # release
|
| 492 |
+
|
| 493 |
+
# You cannot use a wild card and a pre-release, post-release, a dev or
|
| 494 |
+
# local version together so group them with a | and make them optional.
|
| 495 |
+
(?:
|
| 496 |
+
\.\* # Wild card syntax of .*
|
| 497 |
+
|
|
| 498 |
+
(?a: # pre release
|
| 499 |
+
[-_\.]?
|
| 500 |
+
(alpha|beta|preview|pre|a|b|c|rc)
|
| 501 |
+
[-_\.]?
|
| 502 |
+
[0-9]*
|
| 503 |
+
)?
|
| 504 |
+
(?a: # post release
|
| 505 |
+
(?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
|
| 506 |
+
)?
|
| 507 |
+
(?a:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
|
| 508 |
+
(?a:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local
|
| 509 |
+
)?
|
| 510 |
+
)
|
| 511 |
+
|
|
| 512 |
+
(?:
|
| 513 |
+
# The compatible operator requires at least two digits in the
|
| 514 |
+
# release segment.
|
| 515 |
+
(?:~=) # Only match for the compatible operator
|
| 516 |
+
|
| 517 |
+
\s*
|
| 518 |
+
v?
|
| 519 |
+
(?:[0-9]+!)? # epoch
|
| 520 |
+
[0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *)
|
| 521 |
+
(?: # pre release
|
| 522 |
+
[-_\.]?
|
| 523 |
+
(alpha|beta|preview|pre|a|b|c|rc)
|
| 524 |
+
[-_\.]?
|
| 525 |
+
[0-9]*
|
| 526 |
+
)?
|
| 527 |
+
(?: # post release
|
| 528 |
+
(?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
|
| 529 |
+
)?
|
| 530 |
+
(?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
|
| 531 |
+
)
|
| 532 |
+
|
|
| 533 |
+
(?:
|
| 534 |
+
# All other operators only allow a sub set of what the
|
| 535 |
+
# (non)equality operators do. Specifically they do not allow
|
| 536 |
+
# local versions to be specified nor do they allow the prefix
|
| 537 |
+
# matching wild cards.
|
| 538 |
+
(?:<=|>=|<|>)
|
| 539 |
+
|
| 540 |
+
\s*
|
| 541 |
+
v?
|
| 542 |
+
(?:[0-9]+!)? # epoch
|
| 543 |
+
[0-9]+(?:\.[0-9]+)* # release
|
| 544 |
+
(?a: # pre release
|
| 545 |
+
[-_\.]?
|
| 546 |
+
(alpha|beta|preview|pre|a|b|c|rc)
|
| 547 |
+
[-_\.]?
|
| 548 |
+
[0-9]*
|
| 549 |
+
)?
|
| 550 |
+
(?a: # post release
|
| 551 |
+
(?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
|
| 552 |
+
)?
|
| 553 |
+
(?a:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
|
| 554 |
+
)
|
| 555 |
+
)
|
| 556 |
+
"""
|
| 557 |
+
|
| 558 |
+
_regex = re.compile(
|
| 559 |
+
r"\s*" + _specifier_regex_str + r"\s*", re.VERBOSE | re.IGNORECASE
|
| 560 |
+
)
|
| 561 |
+
|
| 562 |
+
_operators: Final = {
|
| 563 |
+
"~=": "compatible",
|
| 564 |
+
"==": "equal",
|
| 565 |
+
"!=": "not_equal",
|
| 566 |
+
"<=": "less_than_equal",
|
| 567 |
+
">=": "greater_than_equal",
|
| 568 |
+
"<": "less_than",
|
| 569 |
+
">": "greater_than",
|
| 570 |
+
"===": "arbitrary",
|
| 571 |
+
}
|
| 572 |
+
|
| 573 |
+
def __init__(self, spec: str = "", prereleases: bool | None = None) -> None:
|
| 574 |
+
"""Initialize a Specifier instance.
|
| 575 |
+
|
| 576 |
+
:param spec:
|
| 577 |
+
The string representation of a specifier which will be parsed and
|
| 578 |
+
normalized before use.
|
| 579 |
+
:param prereleases:
|
| 580 |
+
This tells the specifier if it should accept prerelease versions if
|
| 581 |
+
applicable or not. The default of ``None`` will autodetect it from the
|
| 582 |
+
given specifiers.
|
| 583 |
+
:raises InvalidSpecifier:
|
| 584 |
+
If the given specifier is invalid (i.e. bad syntax).
|
| 585 |
+
"""
|
| 586 |
+
if not self._regex.fullmatch(spec):
|
| 587 |
+
raise InvalidSpecifier(f"Invalid specifier: {spec!r}")
|
| 588 |
+
|
| 589 |
+
spec = spec.strip()
|
| 590 |
+
if spec.startswith("==="):
|
| 591 |
+
operator, version = spec[:3], spec[3:].strip()
|
| 592 |
+
elif spec.startswith(("~=", "==", "!=", "<=", ">=")):
|
| 593 |
+
operator, version = spec[:2], spec[2:].strip()
|
| 594 |
+
else:
|
| 595 |
+
operator, version = spec[:1], spec[1:].strip()
|
| 596 |
+
|
| 597 |
+
self._spec: tuple[str, str] = (operator, version)
|
| 598 |
+
|
| 599 |
+
# Store whether or not this Specifier should accept prereleases
|
| 600 |
+
self._prereleases = prereleases
|
| 601 |
+
|
| 602 |
+
# Specifier version cache
|
| 603 |
+
self._spec_version: tuple[str, Version] | None = None
|
| 604 |
+
|
| 605 |
+
# Populated on first wildcard (==X.*) comparison
|
| 606 |
+
self._wildcard_split: tuple[list[str], int] | None = None
|
| 607 |
+
|
| 608 |
+
# Version range cache (populated by _to_ranges)
|
| 609 |
+
self._ranges: Sequence[_VersionRange] | None = None
|
| 610 |
+
|
| 611 |
+
def _get_spec_version(self, version: str) -> Version | None:
|
| 612 |
+
"""One element cache, as only one spec Version is needed per Specifier."""
|
| 613 |
+
if self._spec_version is not None and self._spec_version[0] == version:
|
| 614 |
+
return self._spec_version[1]
|
| 615 |
+
|
| 616 |
+
version_specifier = _coerce_version(version)
|
| 617 |
+
if version_specifier is None:
|
| 618 |
+
return None
|
| 619 |
+
|
| 620 |
+
self._spec_version = (version, version_specifier)
|
| 621 |
+
return version_specifier
|
| 622 |
+
|
| 623 |
+
def _require_spec_version(self, version: str) -> Version:
|
| 624 |
+
"""Get spec version, asserting it's valid (not for === operator).
|
| 625 |
+
|
| 626 |
+
This method should only be called for operators where version
|
| 627 |
+
strings are guaranteed to be valid PEP 440 versions (not ===).
|
| 628 |
+
"""
|
| 629 |
+
spec_version = self._get_spec_version(version)
|
| 630 |
+
assert spec_version is not None
|
| 631 |
+
return spec_version
|
| 632 |
+
|
| 633 |
+
def _to_ranges(self) -> Sequence[_VersionRange]:
|
| 634 |
+
"""Convert this specifier to sorted, non-overlapping version ranges.
|
| 635 |
+
|
| 636 |
+
Each standard operator maps to one or two ranges. ``===`` is
|
| 637 |
+
modeled as full range (actual check done separately). Cached.
|
| 638 |
+
"""
|
| 639 |
+
if self._ranges is not None:
|
| 640 |
+
return self._ranges
|
| 641 |
+
|
| 642 |
+
op = self.operator
|
| 643 |
+
ver_str = self.version
|
| 644 |
+
|
| 645 |
+
if op == "===":
|
| 646 |
+
self._ranges = _FULL_RANGE
|
| 647 |
+
return _FULL_RANGE
|
| 648 |
+
|
| 649 |
+
if ver_str.endswith(".*"):
|
| 650 |
+
result = self._wildcard_ranges(op, ver_str)
|
| 651 |
+
else:
|
| 652 |
+
result = self._standard_ranges(op, ver_str)
|
| 653 |
+
|
| 654 |
+
self._ranges = result
|
| 655 |
+
return result
|
| 656 |
+
|
| 657 |
+
def _wildcard_ranges(self, op: str, ver_str: str) -> list[_VersionRange]:
|
| 658 |
+
# ==1.2.* -> [1.2.dev0, 1.3.dev0); !=1.2.* -> complement.
|
| 659 |
+
base = self._require_spec_version(ver_str[:-2])
|
| 660 |
+
lower = _base_dev0(base)
|
| 661 |
+
upper = _next_prefix_dev0(base)
|
| 662 |
+
if op == "==":
|
| 663 |
+
return [(_LowerBound(lower, True), _UpperBound(upper, False))]
|
| 664 |
+
# !=
|
| 665 |
+
return [
|
| 666 |
+
(_NEG_INF, _UpperBound(lower, False)),
|
| 667 |
+
(_LowerBound(upper, True), _POS_INF),
|
| 668 |
+
]
|
| 669 |
+
|
| 670 |
+
def _standard_ranges(self, op: str, ver_str: str) -> list[_VersionRange]:
|
| 671 |
+
v = self._require_spec_version(ver_str)
|
| 672 |
+
|
| 673 |
+
if op == ">=":
|
| 674 |
+
return [(_LowerBound(v, True), _POS_INF)]
|
| 675 |
+
|
| 676 |
+
if op == "<=":
|
| 677 |
+
return [
|
| 678 |
+
(
|
| 679 |
+
_NEG_INF,
|
| 680 |
+
_UpperBound(_BoundaryVersion(v, _BoundaryKind.AFTER_LOCALS), True),
|
| 681 |
+
)
|
| 682 |
+
]
|
| 683 |
+
|
| 684 |
+
if op == ">":
|
| 685 |
+
if v.dev is not None:
|
| 686 |
+
# >V.devN: dev versions have no post-releases, so the
|
| 687 |
+
# next real version is V.dev(N+1).
|
| 688 |
+
lower_ver = v.__replace__(dev=v.dev + 1, local=None)
|
| 689 |
+
return [(_LowerBound(lower_ver, True), _POS_INF)]
|
| 690 |
+
if v.post is not None:
|
| 691 |
+
# >V.postN: next real version is V.post(N+1).dev0.
|
| 692 |
+
lower_ver = v.__replace__(post=v.post + 1, dev=0, local=None)
|
| 693 |
+
return [(_LowerBound(lower_ver, True), _POS_INF)]
|
| 694 |
+
# >V (final or pre-release): skip V+local and all V.postN.
|
| 695 |
+
return [
|
| 696 |
+
(
|
| 697 |
+
_LowerBound(_BoundaryVersion(v, _BoundaryKind.AFTER_POSTS), False),
|
| 698 |
+
_POS_INF,
|
| 699 |
+
)
|
| 700 |
+
]
|
| 701 |
+
|
| 702 |
+
if op == "<":
|
| 703 |
+
# <V excludes prereleases of V when V is not a prerelease.
|
| 704 |
+
# V.dev0 is the earliest prerelease of V (final, post, etc.).
|
| 705 |
+
bound = v if v.is_prerelease else v.__replace__(dev=0, local=None)
|
| 706 |
+
if bound <= _MIN_VERSION:
|
| 707 |
+
return []
|
| 708 |
+
return [(_NEG_INF, _UpperBound(bound, False))]
|
| 709 |
+
|
| 710 |
+
# ==, !=: local versions of V match when spec has no local segment.
|
| 711 |
+
has_local = "+" in ver_str
|
| 712 |
+
after_locals = _BoundaryVersion(v, _BoundaryKind.AFTER_LOCALS)
|
| 713 |
+
upper = v if has_local else after_locals
|
| 714 |
+
|
| 715 |
+
if op == "==":
|
| 716 |
+
return [(_LowerBound(v, True), _UpperBound(upper, True))]
|
| 717 |
+
|
| 718 |
+
if op == "!=":
|
| 719 |
+
return [
|
| 720 |
+
(_NEG_INF, _UpperBound(v, False)),
|
| 721 |
+
(_LowerBound(upper, False), _POS_INF),
|
| 722 |
+
]
|
| 723 |
+
|
| 724 |
+
if op == "~=":
|
| 725 |
+
prefix = v.__replace__(release=v.release[:-1])
|
| 726 |
+
return [
|
| 727 |
+
(_LowerBound(v, True), _UpperBound(_next_prefix_dev0(prefix), False))
|
| 728 |
+
]
|
| 729 |
+
|
| 730 |
+
raise ValueError(f"Unknown operator: {op!r}") # pragma: no cover
|
| 731 |
+
|
| 732 |
+
@property
|
| 733 |
+
def prereleases(self) -> bool | None:
|
| 734 |
+
# If there is an explicit prereleases set for this, then we'll just
|
| 735 |
+
# blindly use that.
|
| 736 |
+
if self._prereleases is not None:
|
| 737 |
+
return self._prereleases
|
| 738 |
+
|
| 739 |
+
# Only the "!=" operator does not imply prereleases when
|
| 740 |
+
# the version in the specifier is a prerelease.
|
| 741 |
+
operator, version_str = self._spec
|
| 742 |
+
if operator == "!=":
|
| 743 |
+
return False
|
| 744 |
+
|
| 745 |
+
# The == specifier with trailing .* cannot include prereleases
|
| 746 |
+
# e.g. "==1.0a1.*" is not valid.
|
| 747 |
+
if operator == "==" and version_str.endswith(".*"):
|
| 748 |
+
return False
|
| 749 |
+
|
| 750 |
+
# "===" can have arbitrary string versions, so we cannot parse
|
| 751 |
+
# those, we take prereleases as unknown (None) for those.
|
| 752 |
+
version = self._get_spec_version(version_str)
|
| 753 |
+
if version is None:
|
| 754 |
+
return None
|
| 755 |
+
|
| 756 |
+
# For all other operators, use the check if spec Version
|
| 757 |
+
# object implies pre-releases.
|
| 758 |
+
return version.is_prerelease
|
| 759 |
+
|
| 760 |
+
@prereleases.setter
|
| 761 |
+
def prereleases(self, value: bool | None) -> None:
|
| 762 |
+
self._prereleases = value
|
| 763 |
+
|
| 764 |
+
def __getstate__(self) -> tuple[tuple[str, str], bool | None]:
|
| 765 |
+
# Return state as a 2-item tuple for compactness:
|
| 766 |
+
# ((operator, version), prereleases)
|
| 767 |
+
# Cache members are excluded and will be recomputed on demand.
|
| 768 |
+
return (self._spec, self._prereleases)
|
| 769 |
+
|
| 770 |
+
def __setstate__(self, state: object) -> None:
|
| 771 |
+
# Always discard cached values - they will be recomputed on demand.
|
| 772 |
+
self._spec_version = None
|
| 773 |
+
self._wildcard_split = None
|
| 774 |
+
self._ranges = None
|
| 775 |
+
|
| 776 |
+
if isinstance(state, tuple):
|
| 777 |
+
if len(state) == 2:
|
| 778 |
+
# New format (26.2+): ((operator, version), prereleases)
|
| 779 |
+
spec, prereleases = state
|
| 780 |
+
if _validate_spec(spec) and _validate_pre(prereleases):
|
| 781 |
+
self._spec = spec
|
| 782 |
+
self._prereleases = prereleases
|
| 783 |
+
return
|
| 784 |
+
if len(state) == 2 and isinstance(state[1], dict):
|
| 785 |
+
# Format (packaging 26.0-26.1): (None, {slot: value}).
|
| 786 |
+
_, slot_dict = state
|
| 787 |
+
spec = slot_dict.get("_spec")
|
| 788 |
+
prereleases = slot_dict.get("_prereleases", "invalid")
|
| 789 |
+
if _validate_spec(spec) and _validate_pre(prereleases):
|
| 790 |
+
self._spec = spec
|
| 791 |
+
self._prereleases = prereleases
|
| 792 |
+
return
|
| 793 |
+
if isinstance(state, dict):
|
| 794 |
+
# Old format (packaging <= 25.x, no __slots__): state is a plain dict.
|
| 795 |
+
spec = state.get("_spec")
|
| 796 |
+
prereleases = state.get("_prereleases", "invalid")
|
| 797 |
+
if _validate_spec(spec) and _validate_pre(prereleases):
|
| 798 |
+
self._spec = spec
|
| 799 |
+
self._prereleases = prereleases
|
| 800 |
+
return
|
| 801 |
+
|
| 802 |
+
raise TypeError(f"Cannot restore Specifier from {state!r}")
|
| 803 |
+
|
| 804 |
+
@property
|
| 805 |
+
def operator(self) -> str:
|
| 806 |
+
"""The operator of this specifier.
|
| 807 |
+
|
| 808 |
+
>>> Specifier("==1.2.3").operator
|
| 809 |
+
'=='
|
| 810 |
+
"""
|
| 811 |
+
return self._spec[0]
|
| 812 |
+
|
| 813 |
+
@property
|
| 814 |
+
def version(self) -> str:
|
| 815 |
+
"""The version of this specifier.
|
| 816 |
+
|
| 817 |
+
>>> Specifier("==1.2.3").version
|
| 818 |
+
'1.2.3'
|
| 819 |
+
"""
|
| 820 |
+
return self._spec[1]
|
| 821 |
+
|
| 822 |
+
def __repr__(self) -> str:
|
| 823 |
+
"""A representation of the Specifier that shows all internal state.
|
| 824 |
+
|
| 825 |
+
>>> Specifier('>=1.0.0')
|
| 826 |
+
<Specifier('>=1.0.0')>
|
| 827 |
+
>>> Specifier('>=1.0.0', prereleases=False)
|
| 828 |
+
<Specifier('>=1.0.0', prereleases=False)>
|
| 829 |
+
>>> Specifier('>=1.0.0', prereleases=True)
|
| 830 |
+
<Specifier('>=1.0.0', prereleases=True)>
|
| 831 |
+
"""
|
| 832 |
+
pre = (
|
| 833 |
+
f", prereleases={self.prereleases!r}"
|
| 834 |
+
if self._prereleases is not None
|
| 835 |
+
else ""
|
| 836 |
+
)
|
| 837 |
+
|
| 838 |
+
return f"<{self.__class__.__name__}({str(self)!r}{pre})>"
|
| 839 |
+
|
| 840 |
+
def __str__(self) -> str:
|
| 841 |
+
"""A string representation of the Specifier that can be round-tripped.
|
| 842 |
+
|
| 843 |
+
>>> str(Specifier('>=1.0.0'))
|
| 844 |
+
'>=1.0.0'
|
| 845 |
+
>>> str(Specifier('>=1.0.0', prereleases=False))
|
| 846 |
+
'>=1.0.0'
|
| 847 |
+
"""
|
| 848 |
+
return "{}{}".format(*self._spec)
|
| 849 |
+
|
| 850 |
+
@property
|
| 851 |
+
def _canonical_spec(self) -> tuple[str, str]:
|
| 852 |
+
operator, version = self._spec
|
| 853 |
+
if operator == "===" or version.endswith(".*"):
|
| 854 |
+
return operator, version
|
| 855 |
+
|
| 856 |
+
spec_version = self._require_spec_version(version)
|
| 857 |
+
|
| 858 |
+
canonical_version = canonicalize_version(
|
| 859 |
+
spec_version, strip_trailing_zero=(operator != "~=")
|
| 860 |
+
)
|
| 861 |
+
|
| 862 |
+
return operator, canonical_version
|
| 863 |
+
|
| 864 |
+
def __hash__(self) -> int:
|
| 865 |
+
return hash(self._canonical_spec)
|
| 866 |
+
|
| 867 |
+
def __eq__(self, other: object) -> bool:
|
| 868 |
+
"""Whether or not the two Specifier-like objects are equal.
|
| 869 |
+
|
| 870 |
+
:param other: The other object to check against.
|
| 871 |
+
|
| 872 |
+
The value of :attr:`prereleases` is ignored.
|
| 873 |
+
|
| 874 |
+
>>> Specifier("==1.2.3") == Specifier("== 1.2.3.0")
|
| 875 |
+
True
|
| 876 |
+
>>> (Specifier("==1.2.3", prereleases=False) ==
|
| 877 |
+
... Specifier("==1.2.3", prereleases=True))
|
| 878 |
+
True
|
| 879 |
+
>>> Specifier("==1.2.3") == "==1.2.3"
|
| 880 |
+
True
|
| 881 |
+
>>> Specifier("==1.2.3") == Specifier("==1.2.4")
|
| 882 |
+
False
|
| 883 |
+
>>> Specifier("==1.2.3") == Specifier("~=1.2.3")
|
| 884 |
+
False
|
| 885 |
+
"""
|
| 886 |
+
if isinstance(other, str):
|
| 887 |
+
try:
|
| 888 |
+
other = self.__class__(str(other))
|
| 889 |
+
except InvalidSpecifier:
|
| 890 |
+
return NotImplemented
|
| 891 |
+
elif not isinstance(other, self.__class__):
|
| 892 |
+
return NotImplemented
|
| 893 |
+
|
| 894 |
+
return self._canonical_spec == other._canonical_spec
|
| 895 |
+
|
| 896 |
+
def _get_operator(self, op: str) -> CallableOperator:
|
| 897 |
+
operator_callable: CallableOperator = getattr(
|
| 898 |
+
self, f"_compare_{self._operators[op]}"
|
| 899 |
+
)
|
| 900 |
+
return operator_callable
|
| 901 |
+
|
| 902 |
+
def _compare_compatible(self, prospective: Version, spec: str) -> bool:
|
| 903 |
+
# Compatible releases have an equivalent combination of >= and ==. That
|
| 904 |
+
# is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to
|
| 905 |
+
# implement this in terms of the other specifiers instead of
|
| 906 |
+
# implementing it ourselves. The only thing we need to do is construct
|
| 907 |
+
# the other specifiers.
|
| 908 |
+
|
| 909 |
+
# We want everything but the last item in the version, but we want to
|
| 910 |
+
# ignore suffix segments.
|
| 911 |
+
prefix = _version_join(
|
| 912 |
+
list(itertools.takewhile(_is_not_suffix, _version_split(spec)))[:-1]
|
| 913 |
+
)
|
| 914 |
+
|
| 915 |
+
# Add the prefix notation to the end of our string
|
| 916 |
+
prefix += ".*"
|
| 917 |
+
|
| 918 |
+
return (self._compare_greater_than_equal(prospective, spec)) and (
|
| 919 |
+
self._compare_equal(prospective, prefix)
|
| 920 |
+
)
|
| 921 |
+
|
| 922 |
+
def _get_wildcard_split(self, spec: str) -> tuple[list[str], int]:
|
| 923 |
+
"""Cached split of a wildcard spec into components and numeric length.
|
| 924 |
+
|
| 925 |
+
>>> Specifier("==1.*")._get_wildcard_split("1.*")
|
| 926 |
+
(['0', '1'], 2)
|
| 927 |
+
>>> Specifier("==3.10.*")._get_wildcard_split("3.10.*")
|
| 928 |
+
(['0', '3', '10'], 3)
|
| 929 |
+
"""
|
| 930 |
+
wildcard_split = self._wildcard_split
|
| 931 |
+
if wildcard_split is None:
|
| 932 |
+
normalized = canonicalize_version(spec[:-2], strip_trailing_zero=False)
|
| 933 |
+
split_spec = _version_split(normalized)
|
| 934 |
+
wildcard_split = (split_spec, _numeric_prefix_len(split_spec))
|
| 935 |
+
self._wildcard_split = wildcard_split
|
| 936 |
+
return wildcard_split
|
| 937 |
+
|
| 938 |
+
def _compare_equal(self, prospective: Version, spec: str) -> bool:
|
| 939 |
+
# We need special logic to handle prefix matching
|
| 940 |
+
if spec.endswith(".*"):
|
| 941 |
+
split_spec, spec_numeric_len = self._get_wildcard_split(spec)
|
| 942 |
+
|
| 943 |
+
# In the case of prefix matching we want to ignore local segment.
|
| 944 |
+
normalized_prospective = canonicalize_version(
|
| 945 |
+
_public_version(prospective), strip_trailing_zero=False
|
| 946 |
+
)
|
| 947 |
+
# Split the prospective version out by bangs and dots, and pretend
|
| 948 |
+
# that there is an implicit dot in between a release segment and
|
| 949 |
+
# a pre-release segment.
|
| 950 |
+
split_prospective = _version_split(normalized_prospective)
|
| 951 |
+
|
| 952 |
+
# 0-pad the prospective version before shortening it to get the correct
|
| 953 |
+
# shortened version.
|
| 954 |
+
padded_prospective = _left_pad(split_prospective, spec_numeric_len)
|
| 955 |
+
|
| 956 |
+
# Shorten the prospective version to be the same length as the spec
|
| 957 |
+
# so that we can determine if the specifier is a prefix of the
|
| 958 |
+
# prospective version or not.
|
| 959 |
+
shortened_prospective = padded_prospective[: len(split_spec)]
|
| 960 |
+
|
| 961 |
+
return shortened_prospective == split_spec
|
| 962 |
+
else:
|
| 963 |
+
# Convert our spec string into a Version
|
| 964 |
+
spec_version = self._require_spec_version(spec)
|
| 965 |
+
|
| 966 |
+
# If the specifier does not have a local segment, then we want to
|
| 967 |
+
# act as if the prospective version also does not have a local
|
| 968 |
+
# segment.
|
| 969 |
+
if not spec_version.local:
|
| 970 |
+
prospective = _public_version(prospective)
|
| 971 |
+
|
| 972 |
+
return prospective == spec_version
|
| 973 |
+
|
| 974 |
+
def _compare_not_equal(self, prospective: Version, spec: str) -> bool:
|
| 975 |
+
return not self._compare_equal(prospective, spec)
|
| 976 |
+
|
| 977 |
+
def _compare_less_than_equal(self, prospective: Version, spec: str) -> bool:
|
| 978 |
+
# NB: Local version identifiers are NOT permitted in the version
|
| 979 |
+
# specifier, so local version labels can be universally removed from
|
| 980 |
+
# the prospective version.
|
| 981 |
+
return _public_version(prospective) <= self._require_spec_version(spec)
|
| 982 |
+
|
| 983 |
+
def _compare_greater_than_equal(self, prospective: Version, spec: str) -> bool:
|
| 984 |
+
# NB: Local version identifiers are NOT permitted in the version
|
| 985 |
+
# specifier, so local version labels can be universally removed from
|
| 986 |
+
# the prospective version.
|
| 987 |
+
return _public_version(prospective) >= self._require_spec_version(spec)
|
| 988 |
+
|
| 989 |
+
def _compare_less_than(self, prospective: Version, spec_str: str) -> bool:
|
| 990 |
+
# Convert our spec to a Version instance, since we'll want to work with
|
| 991 |
+
# it as a version.
|
| 992 |
+
spec = self._require_spec_version(spec_str)
|
| 993 |
+
|
| 994 |
+
# Check to see if the prospective version is less than the spec
|
| 995 |
+
# version. If it's not we can short circuit and just return False now
|
| 996 |
+
# instead of doing extra unneeded work.
|
| 997 |
+
if not prospective < spec:
|
| 998 |
+
return False
|
| 999 |
+
|
| 1000 |
+
# The spec says: "<V MUST NOT allow a pre-release of the specified
|
| 1001 |
+
# version unless the specified version is itself a pre-release."
|
| 1002 |
+
if (
|
| 1003 |
+
not spec.is_prerelease
|
| 1004 |
+
and prospective.is_prerelease
|
| 1005 |
+
and prospective >= _earliest_prerelease(spec)
|
| 1006 |
+
):
|
| 1007 |
+
return False
|
| 1008 |
+
|
| 1009 |
+
# If we've gotten to here, it means that prospective version is both
|
| 1010 |
+
# less than the spec version *and* it's not a pre-release of the same
|
| 1011 |
+
# version in the spec.
|
| 1012 |
+
return True
|
| 1013 |
+
|
| 1014 |
+
def _compare_greater_than(self, prospective: Version, spec_str: str) -> bool:
|
| 1015 |
+
# Convert our spec to a Version instance, since we'll want to work with
|
| 1016 |
+
# it as a version.
|
| 1017 |
+
spec = self._require_spec_version(spec_str)
|
| 1018 |
+
|
| 1019 |
+
# Check to see if the prospective version is greater than the spec
|
| 1020 |
+
# version. If it's not we can short circuit and just return False now
|
| 1021 |
+
# instead of doing extra unneeded work.
|
| 1022 |
+
if not prospective > spec:
|
| 1023 |
+
return False
|
| 1024 |
+
|
| 1025 |
+
# The spec says: ">V MUST NOT allow a post-release of the specified
|
| 1026 |
+
# version unless the specified version is itself a post-release."
|
| 1027 |
+
if (
|
| 1028 |
+
not spec.is_postrelease
|
| 1029 |
+
and prospective.is_postrelease
|
| 1030 |
+
and _post_base(prospective) == spec
|
| 1031 |
+
):
|
| 1032 |
+
return False
|
| 1033 |
+
|
| 1034 |
+
# Per the spec: ">V MUST NOT match a local version of the specified
|
| 1035 |
+
# version". A "local version of V" is any version whose public part
|
| 1036 |
+
# equals V. So >1.0a1 must not match 1.0a1+local, but must still
|
| 1037 |
+
# match 1.0a2+local.
|
| 1038 |
+
if prospective.local is not None and _public_version(prospective) == spec:
|
| 1039 |
+
return False
|
| 1040 |
+
|
| 1041 |
+
# If we've gotten to here, it means that prospective version is both
|
| 1042 |
+
# greater than the spec version *and* it's not a pre-release of the
|
| 1043 |
+
# same version in the spec.
|
| 1044 |
+
return True
|
| 1045 |
+
|
| 1046 |
+
def _compare_arbitrary(self, prospective: Version | str, spec: str) -> bool:
|
| 1047 |
+
return str(prospective).lower() == str(spec).lower()
|
| 1048 |
+
|
| 1049 |
+
def __contains__(self, item: str | Version) -> bool:
|
| 1050 |
+
"""Return whether or not the item is contained in this specifier.
|
| 1051 |
+
|
| 1052 |
+
:param item: The item to check for.
|
| 1053 |
+
|
| 1054 |
+
This is used for the ``in`` operator and behaves the same as
|
| 1055 |
+
:meth:`contains` with no ``prereleases`` argument passed.
|
| 1056 |
+
|
| 1057 |
+
>>> "1.2.3" in Specifier(">=1.2.3")
|
| 1058 |
+
True
|
| 1059 |
+
>>> Version("1.2.3") in Specifier(">=1.2.3")
|
| 1060 |
+
True
|
| 1061 |
+
>>> "1.0.0" in Specifier(">=1.2.3")
|
| 1062 |
+
False
|
| 1063 |
+
>>> "1.3.0a1" in Specifier(">=1.2.3")
|
| 1064 |
+
True
|
| 1065 |
+
>>> "1.3.0a1" in Specifier(">=1.2.3", prereleases=True)
|
| 1066 |
+
True
|
| 1067 |
+
"""
|
| 1068 |
+
return self.contains(item)
|
| 1069 |
+
|
| 1070 |
+
def contains(self, item: UnparsedVersion, prereleases: bool | None = None) -> bool:
|
| 1071 |
+
"""Return whether or not the item is contained in this specifier.
|
| 1072 |
+
|
| 1073 |
+
:param item:
|
| 1074 |
+
The item to check for, which can be a version string or a
|
| 1075 |
+
:class:`Version` instance.
|
| 1076 |
+
:param prereleases:
|
| 1077 |
+
Whether or not to match prereleases with this Specifier. If set to
|
| 1078 |
+
``None`` (the default), it will follow the recommendation from
|
| 1079 |
+
:pep:`440` and match prereleases, as there are no other versions.
|
| 1080 |
+
|
| 1081 |
+
>>> Specifier(">=1.2.3").contains("1.2.3")
|
| 1082 |
+
True
|
| 1083 |
+
>>> Specifier(">=1.2.3").contains(Version("1.2.3"))
|
| 1084 |
+
True
|
| 1085 |
+
>>> Specifier(">=1.2.3").contains("1.0.0")
|
| 1086 |
+
False
|
| 1087 |
+
>>> Specifier(">=1.2.3").contains("1.3.0a1")
|
| 1088 |
+
True
|
| 1089 |
+
>>> Specifier(">=1.2.3", prereleases=False).contains("1.3.0a1")
|
| 1090 |
+
False
|
| 1091 |
+
>>> Specifier(">=1.2.3").contains("1.3.0a1")
|
| 1092 |
+
True
|
| 1093 |
+
"""
|
| 1094 |
+
|
| 1095 |
+
return bool(list(self.filter([item], prereleases=prereleases)))
|
| 1096 |
+
|
| 1097 |
+
@typing.overload
|
| 1098 |
+
def filter(
|
| 1099 |
+
self,
|
| 1100 |
+
iterable: Iterable[UnparsedVersionVar],
|
| 1101 |
+
prereleases: bool | None = None,
|
| 1102 |
+
key: None = ...,
|
| 1103 |
+
) -> Iterator[UnparsedVersionVar]: ...
|
| 1104 |
+
|
| 1105 |
+
@typing.overload
|
| 1106 |
+
def filter(
|
| 1107 |
+
self,
|
| 1108 |
+
iterable: Iterable[T],
|
| 1109 |
+
prereleases: bool | None = None,
|
| 1110 |
+
key: Callable[[T], UnparsedVersion] = ...,
|
| 1111 |
+
) -> Iterator[T]: ...
|
| 1112 |
+
|
| 1113 |
+
def filter(
|
| 1114 |
+
self,
|
| 1115 |
+
iterable: Iterable[Any],
|
| 1116 |
+
prereleases: bool | None = None,
|
| 1117 |
+
key: Callable[[Any], UnparsedVersion] | None = None,
|
| 1118 |
+
) -> Iterator[Any]:
|
| 1119 |
+
"""Filter items in the given iterable, that match the specifier.
|
| 1120 |
+
|
| 1121 |
+
:param iterable:
|
| 1122 |
+
An iterable that can contain version strings and :class:`Version` instances.
|
| 1123 |
+
The items in the iterable will be filtered according to the specifier.
|
| 1124 |
+
:param prereleases:
|
| 1125 |
+
Whether or not to allow prereleases in the returned iterator. If set to
|
| 1126 |
+
``None`` (the default), it will follow the recommendation from :pep:`440`
|
| 1127 |
+
and match prereleases if there are no other versions.
|
| 1128 |
+
:param key:
|
| 1129 |
+
A callable that takes a single argument (an item from the iterable) and
|
| 1130 |
+
returns a version string or :class:`Version` instance to be used for
|
| 1131 |
+
filtering.
|
| 1132 |
+
|
| 1133 |
+
>>> list(Specifier(">=1.2.3").filter(["1.2", "1.3", "1.5a1"]))
|
| 1134 |
+
['1.3']
|
| 1135 |
+
>>> list(Specifier(">=1.2.3").filter(["1.2", "1.2.3", "1.3", Version("1.4")]))
|
| 1136 |
+
['1.2.3', '1.3', <Version('1.4')>]
|
| 1137 |
+
>>> list(Specifier(">=1.2.3").filter(["1.2", "1.5a1"]))
|
| 1138 |
+
['1.5a1']
|
| 1139 |
+
>>> list(Specifier(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True))
|
| 1140 |
+
['1.3', '1.5a1']
|
| 1141 |
+
>>> list(Specifier(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"]))
|
| 1142 |
+
['1.3', '1.5a1']
|
| 1143 |
+
>>> list(Specifier(">=1.2.3").filter(
|
| 1144 |
+
... [{"ver": "1.2"}, {"ver": "1.3"}],
|
| 1145 |
+
... key=lambda x: x["ver"]))
|
| 1146 |
+
[{'ver': '1.3'}]
|
| 1147 |
+
"""
|
| 1148 |
+
prereleases_versions = []
|
| 1149 |
+
found_non_prereleases = False
|
| 1150 |
+
|
| 1151 |
+
# Determine if to include prereleases by default
|
| 1152 |
+
include_prereleases = (
|
| 1153 |
+
prereleases if prereleases is not None else self.prereleases
|
| 1154 |
+
)
|
| 1155 |
+
|
| 1156 |
+
# Get the matching operator
|
| 1157 |
+
operator_callable = self._get_operator(self.operator)
|
| 1158 |
+
|
| 1159 |
+
# Filter versions
|
| 1160 |
+
for version in iterable:
|
| 1161 |
+
parsed_version = _coerce_version(version if key is None else key(version))
|
| 1162 |
+
match = False
|
| 1163 |
+
if parsed_version is None:
|
| 1164 |
+
# === operator can match arbitrary (non-version) strings
|
| 1165 |
+
if self.operator == "===" and self._compare_arbitrary(
|
| 1166 |
+
version, self.version
|
| 1167 |
+
):
|
| 1168 |
+
yield version
|
| 1169 |
+
elif self.operator == "===":
|
| 1170 |
+
match = self._compare_arbitrary(
|
| 1171 |
+
version if key is None else key(version), self.version
|
| 1172 |
+
)
|
| 1173 |
+
else:
|
| 1174 |
+
match = operator_callable(parsed_version, self.version)
|
| 1175 |
+
|
| 1176 |
+
if match and parsed_version is not None:
|
| 1177 |
+
# If it's not a prerelease or prereleases are allowed, yield it directly
|
| 1178 |
+
if not parsed_version.is_prerelease or include_prereleases:
|
| 1179 |
+
found_non_prereleases = True
|
| 1180 |
+
yield version
|
| 1181 |
+
# Otherwise collect prereleases for potential later use
|
| 1182 |
+
elif prereleases is None and self._prereleases is not False:
|
| 1183 |
+
prereleases_versions.append(version)
|
| 1184 |
+
|
| 1185 |
+
# If no non-prereleases were found and prereleases weren't
|
| 1186 |
+
# explicitly forbidden, yield the collected prereleases
|
| 1187 |
+
if (
|
| 1188 |
+
not found_non_prereleases
|
| 1189 |
+
and prereleases is None
|
| 1190 |
+
and self._prereleases is not False
|
| 1191 |
+
):
|
| 1192 |
+
yield from prereleases_versions
|
| 1193 |
+
|
| 1194 |
+
|
| 1195 |
+
_prefix_regex = re.compile(r"([0-9]+)((?:a|b|c|rc)[0-9]+)")
|
| 1196 |
+
|
| 1197 |
+
|
| 1198 |
+
def _pep440_filter_prereleases(
|
| 1199 |
+
iterable: Iterable[Any], key: Callable[[Any], UnparsedVersion] | None
|
| 1200 |
+
) -> Iterator[Any]:
|
| 1201 |
+
"""Filter per PEP 440: exclude prereleases unless no finals exist."""
|
| 1202 |
+
# Two lists used:
|
| 1203 |
+
# * all_nonfinal to preserve order if no finals exist
|
| 1204 |
+
# * arbitrary_strings for streaming when first final found
|
| 1205 |
+
all_nonfinal: list[Any] = []
|
| 1206 |
+
arbitrary_strings: list[Any] = []
|
| 1207 |
+
|
| 1208 |
+
found_final = False
|
| 1209 |
+
for item in iterable:
|
| 1210 |
+
parsed = _coerce_version(item if key is None else key(item))
|
| 1211 |
+
|
| 1212 |
+
if parsed is None:
|
| 1213 |
+
# Arbitrary strings are always included as it is not
|
| 1214 |
+
# possible to determine if they are prereleases,
|
| 1215 |
+
# and they have already passed all specifiers.
|
| 1216 |
+
if found_final:
|
| 1217 |
+
yield item
|
| 1218 |
+
else:
|
| 1219 |
+
arbitrary_strings.append(item)
|
| 1220 |
+
all_nonfinal.append(item)
|
| 1221 |
+
continue
|
| 1222 |
+
|
| 1223 |
+
if not parsed.is_prerelease:
|
| 1224 |
+
# Final release found - flush arbitrary strings, then yield
|
| 1225 |
+
if not found_final:
|
| 1226 |
+
yield from arbitrary_strings
|
| 1227 |
+
found_final = True
|
| 1228 |
+
yield item
|
| 1229 |
+
continue
|
| 1230 |
+
|
| 1231 |
+
# Prerelease - buffer if no finals yet, otherwise skip
|
| 1232 |
+
if not found_final:
|
| 1233 |
+
all_nonfinal.append(item)
|
| 1234 |
+
|
| 1235 |
+
# No finals found - yield all buffered items
|
| 1236 |
+
if not found_final:
|
| 1237 |
+
yield from all_nonfinal
|
| 1238 |
+
|
| 1239 |
+
|
| 1240 |
+
def _version_split(version: str) -> list[str]:
|
| 1241 |
+
"""Split version into components.
|
| 1242 |
+
|
| 1243 |
+
The split components are intended for version comparison. The logic does
|
| 1244 |
+
not attempt to retain the original version string, so joining the
|
| 1245 |
+
components back with :func:`_version_join` may not produce the original
|
| 1246 |
+
version string.
|
| 1247 |
+
"""
|
| 1248 |
+
result: list[str] = []
|
| 1249 |
+
|
| 1250 |
+
epoch, _, rest = version.rpartition("!")
|
| 1251 |
+
result.append(epoch or "0")
|
| 1252 |
+
|
| 1253 |
+
for item in rest.split("."):
|
| 1254 |
+
match = _prefix_regex.fullmatch(item)
|
| 1255 |
+
if match:
|
| 1256 |
+
result.extend(match.groups())
|
| 1257 |
+
else:
|
| 1258 |
+
result.append(item)
|
| 1259 |
+
return result
|
| 1260 |
+
|
| 1261 |
+
|
| 1262 |
+
def _version_join(components: list[str]) -> str:
|
| 1263 |
+
"""Join split version components into a version string.
|
| 1264 |
+
|
| 1265 |
+
This function assumes the input came from :func:`_version_split`, where the
|
| 1266 |
+
first component must be the epoch (either empty or numeric), and all other
|
| 1267 |
+
components numeric.
|
| 1268 |
+
"""
|
| 1269 |
+
epoch, *rest = components
|
| 1270 |
+
return f"{epoch}!{'.'.join(rest)}"
|
| 1271 |
+
|
| 1272 |
+
|
| 1273 |
+
def _is_not_suffix(segment: str) -> bool:
|
| 1274 |
+
return not any(
|
| 1275 |
+
segment.startswith(prefix) for prefix in ("dev", "a", "b", "rc", "post")
|
| 1276 |
+
)
|
| 1277 |
+
|
| 1278 |
+
|
| 1279 |
+
def _numeric_prefix_len(split: list[str]) -> int:
|
| 1280 |
+
"""Count leading numeric components in a :func:`_version_split` result.
|
| 1281 |
+
|
| 1282 |
+
>>> _numeric_prefix_len(["0", "1", "2", "a1"])
|
| 1283 |
+
3
|
| 1284 |
+
"""
|
| 1285 |
+
count = 0
|
| 1286 |
+
for segment in split:
|
| 1287 |
+
if not segment.isdigit():
|
| 1288 |
+
break
|
| 1289 |
+
count += 1
|
| 1290 |
+
return count
|
| 1291 |
+
|
| 1292 |
+
|
| 1293 |
+
def _left_pad(split: list[str], target_numeric_len: int) -> list[str]:
|
| 1294 |
+
"""Pad a :func:`_version_split` result with ``"0"`` segments to reach
|
| 1295 |
+
``target_numeric_len`` numeric components. Suffix segments are preserved.
|
| 1296 |
+
|
| 1297 |
+
>>> _left_pad(["0", "1", "a1"], 4)
|
| 1298 |
+
['0', '1', '0', '0', 'a1']
|
| 1299 |
+
"""
|
| 1300 |
+
numeric_len = _numeric_prefix_len(split)
|
| 1301 |
+
pad_needed = target_numeric_len - numeric_len
|
| 1302 |
+
if pad_needed <= 0:
|
| 1303 |
+
return split
|
| 1304 |
+
return [*split[:numeric_len], *(["0"] * pad_needed), *split[numeric_len:]]
|
| 1305 |
+
|
| 1306 |
+
|
| 1307 |
+
def _operator_cost(op_entry: tuple[CallableOperator, str, str]) -> int:
|
| 1308 |
+
"""Sort key for Cost Based Ordering of specifier operators in _filter_versions.
|
| 1309 |
+
|
| 1310 |
+
Operators run sequentially on a shrinking candidate set, so operators that
|
| 1311 |
+
reject the most versions should run first to minimize work for later ones.
|
| 1312 |
+
|
| 1313 |
+
Tier 0: Exact equality (==, ===), likely to narrow candidates to one version
|
| 1314 |
+
Tier 1: Range checks (>=, <=, >, <), cheap and usually reject a large portion
|
| 1315 |
+
Tier 2: Wildcard equality (==.*) and compatible release (~=), more expensive
|
| 1316 |
+
Tier 3: Exact !=, cheap but rarely rejects
|
| 1317 |
+
Tier 4: Wildcard !=.*, expensive and rarely rejects
|
| 1318 |
+
"""
|
| 1319 |
+
_, ver, op = op_entry
|
| 1320 |
+
if op == "==":
|
| 1321 |
+
return 0 if not ver.endswith(".*") else 2
|
| 1322 |
+
if op in (">=", "<=", ">", "<"):
|
| 1323 |
+
return 1
|
| 1324 |
+
if op == "~=":
|
| 1325 |
+
return 2
|
| 1326 |
+
if op == "!=":
|
| 1327 |
+
return 3 if not ver.endswith(".*") else 4
|
| 1328 |
+
if op == "===":
|
| 1329 |
+
return 0
|
| 1330 |
+
|
| 1331 |
+
raise ValueError(f"Unknown operator: {op!r}") # pragma: no cover
|
| 1332 |
+
|
| 1333 |
+
|
| 1334 |
+
class SpecifierSet(BaseSpecifier):
|
| 1335 |
+
"""This class abstracts handling of a set of version specifiers.
|
| 1336 |
+
|
| 1337 |
+
It can be passed a single specifier (``>=3.0``), a comma-separated list of
|
| 1338 |
+
specifiers (``>=3.0,!=3.1``), or no specifier at all.
|
| 1339 |
+
|
| 1340 |
+
Instances are safe to serialize with :mod:`pickle`. They use a stable
|
| 1341 |
+
format so the same pickle can be loaded in future packaging
|
| 1342 |
+
releases.
|
| 1343 |
+
|
| 1344 |
+
.. versionchanged:: 26.2
|
| 1345 |
+
|
| 1346 |
+
Added a stable pickle format. Pickles created with
|
| 1347 |
+
packaging 26.2+ can be unpickled with future releases.
|
| 1348 |
+
Backward compatibility with pickles from
|
| 1349 |
+
packaging < 26.2 is supported but may be removed in a future
|
| 1350 |
+
release.
|
| 1351 |
+
"""
|
| 1352 |
+
|
| 1353 |
+
__slots__ = (
|
| 1354 |
+
"_canonicalized",
|
| 1355 |
+
"_has_arbitrary",
|
| 1356 |
+
"_is_unsatisfiable",
|
| 1357 |
+
"_prereleases",
|
| 1358 |
+
"_resolved_ops",
|
| 1359 |
+
"_specs",
|
| 1360 |
+
)
|
| 1361 |
+
|
| 1362 |
+
def __init__(
|
| 1363 |
+
self,
|
| 1364 |
+
specifiers: str | Iterable[Specifier] = "",
|
| 1365 |
+
prereleases: bool | None = None,
|
| 1366 |
+
) -> None:
|
| 1367 |
+
"""Initialize a SpecifierSet instance.
|
| 1368 |
+
|
| 1369 |
+
:param specifiers:
|
| 1370 |
+
The string representation of a specifier or a comma-separated list of
|
| 1371 |
+
specifiers which will be parsed and normalized before use.
|
| 1372 |
+
May also be an iterable of ``Specifier`` instances, which will be used
|
| 1373 |
+
as is.
|
| 1374 |
+
:param prereleases:
|
| 1375 |
+
This tells the SpecifierSet if it should accept prerelease versions if
|
| 1376 |
+
applicable or not. The default of ``None`` will autodetect it from the
|
| 1377 |
+
given specifiers.
|
| 1378 |
+
|
| 1379 |
+
:raises InvalidSpecifier:
|
| 1380 |
+
If the given ``specifiers`` are not parseable than this exception will be
|
| 1381 |
+
raised.
|
| 1382 |
+
"""
|
| 1383 |
+
|
| 1384 |
+
if isinstance(specifiers, str):
|
| 1385 |
+
# Split on `,` to break each individual specifier into its own item, and
|
| 1386 |
+
# strip each item to remove leading/trailing whitespace.
|
| 1387 |
+
split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
|
| 1388 |
+
|
| 1389 |
+
self._specs: tuple[Specifier, ...] = tuple(map(Specifier, split_specifiers))
|
| 1390 |
+
# Fast substring check; avoids iterating parsed specs.
|
| 1391 |
+
self._has_arbitrary = "===" in specifiers
|
| 1392 |
+
else:
|
| 1393 |
+
self._specs = tuple(specifiers)
|
| 1394 |
+
# Substring check works for both Specifier objects and plain
|
| 1395 |
+
# strings (setuptools passes lists of strings).
|
| 1396 |
+
self._has_arbitrary = any("===" in str(s) for s in self._specs)
|
| 1397 |
+
|
| 1398 |
+
self._canonicalized = len(self._specs) <= 1
|
| 1399 |
+
self._resolved_ops: list[tuple[CallableOperator, str, str]] | None = None
|
| 1400 |
+
|
| 1401 |
+
# Store our prereleases value so we can use it later to determine if
|
| 1402 |
+
# we accept prereleases or not.
|
| 1403 |
+
self._prereleases = prereleases
|
| 1404 |
+
|
| 1405 |
+
self._is_unsatisfiable: bool | None = None
|
| 1406 |
+
|
| 1407 |
+
def _canonical_specs(self) -> tuple[Specifier, ...]:
|
| 1408 |
+
"""Deduplicate, sort, and cache specs for order-sensitive operations."""
|
| 1409 |
+
if not self._canonicalized:
|
| 1410 |
+
self._specs = tuple(dict.fromkeys(sorted(self._specs, key=str)))
|
| 1411 |
+
self._canonicalized = True
|
| 1412 |
+
self._resolved_ops = None
|
| 1413 |
+
self._is_unsatisfiable = None
|
| 1414 |
+
return self._specs
|
| 1415 |
+
|
| 1416 |
+
@property
|
| 1417 |
+
def prereleases(self) -> bool | None:
|
| 1418 |
+
# If we have been given an explicit prerelease modifier, then we'll
|
| 1419 |
+
# pass that through here.
|
| 1420 |
+
if self._prereleases is not None:
|
| 1421 |
+
return self._prereleases
|
| 1422 |
+
|
| 1423 |
+
# If we don't have any specifiers, and we don't have a forced value,
|
| 1424 |
+
# then we'll just return None since we don't know if this should have
|
| 1425 |
+
# pre-releases or not.
|
| 1426 |
+
if not self._specs:
|
| 1427 |
+
return None
|
| 1428 |
+
|
| 1429 |
+
# Otherwise we'll see if any of the given specifiers accept
|
| 1430 |
+
# prereleases, if any of them do we'll return True, otherwise False.
|
| 1431 |
+
if any(s.prereleases for s in self._specs):
|
| 1432 |
+
return True
|
| 1433 |
+
|
| 1434 |
+
return None
|
| 1435 |
+
|
| 1436 |
+
@prereleases.setter
|
| 1437 |
+
def prereleases(self, value: bool | None) -> None:
|
| 1438 |
+
self._prereleases = value
|
| 1439 |
+
self._is_unsatisfiable = None
|
| 1440 |
+
|
| 1441 |
+
def __getstate__(self) -> tuple[tuple[Specifier, ...], bool | None]:
|
| 1442 |
+
# Return state as a 2-item tuple for compactness:
|
| 1443 |
+
# (specs, prereleases)
|
| 1444 |
+
# Cache members are excluded and will be recomputed on demand.
|
| 1445 |
+
return (self._specs, self._prereleases)
|
| 1446 |
+
|
| 1447 |
+
def __setstate__(self, state: object) -> None:
|
| 1448 |
+
# Always discard cached values - they will be recomputed on demand.
|
| 1449 |
+
self._resolved_ops = None
|
| 1450 |
+
self._is_unsatisfiable = None
|
| 1451 |
+
|
| 1452 |
+
if isinstance(state, tuple):
|
| 1453 |
+
if len(state) == 2:
|
| 1454 |
+
# New format (26.2+): (specs, prereleases)
|
| 1455 |
+
specs, prereleases = state
|
| 1456 |
+
if (
|
| 1457 |
+
isinstance(specs, tuple)
|
| 1458 |
+
and all(isinstance(s, Specifier) for s in specs)
|
| 1459 |
+
and _validate_pre(prereleases)
|
| 1460 |
+
):
|
| 1461 |
+
self._specs = specs
|
| 1462 |
+
self._prereleases = prereleases
|
| 1463 |
+
self._canonicalized = len(specs) <= 1
|
| 1464 |
+
self._has_arbitrary = any("===" in str(s) for s in specs)
|
| 1465 |
+
return
|
| 1466 |
+
if len(state) == 2 and isinstance(state[1], dict):
|
| 1467 |
+
# Format (packaging 26.0-26.1): (None, {slot: value}).
|
| 1468 |
+
_, slot_dict = state
|
| 1469 |
+
specs = slot_dict.get("_specs", ())
|
| 1470 |
+
prereleases = slot_dict.get("_prereleases")
|
| 1471 |
+
# Convert frozenset to tuple (26.0 stored as frozenset)
|
| 1472 |
+
if isinstance(specs, frozenset):
|
| 1473 |
+
specs = tuple(sorted(specs, key=str))
|
| 1474 |
+
if (
|
| 1475 |
+
isinstance(specs, tuple)
|
| 1476 |
+
and all(isinstance(s, Specifier) for s in specs)
|
| 1477 |
+
and _validate_pre(prereleases)
|
| 1478 |
+
):
|
| 1479 |
+
self._specs = specs
|
| 1480 |
+
self._prereleases = prereleases
|
| 1481 |
+
self._canonicalized = len(self._specs) <= 1
|
| 1482 |
+
self._has_arbitrary = any("===" in str(s) for s in self._specs)
|
| 1483 |
+
return
|
| 1484 |
+
if isinstance(state, dict):
|
| 1485 |
+
# Old format (packaging <= 25.x, no __slots__): state is a plain dict.
|
| 1486 |
+
specs = state.get("_specs", ())
|
| 1487 |
+
prereleases = state.get("_prereleases")
|
| 1488 |
+
# Convert frozenset to tuple (26.0 stored as frozenset)
|
| 1489 |
+
if isinstance(specs, frozenset):
|
| 1490 |
+
specs = tuple(sorted(specs, key=str))
|
| 1491 |
+
if (
|
| 1492 |
+
isinstance(specs, tuple)
|
| 1493 |
+
and all(isinstance(s, Specifier) for s in specs)
|
| 1494 |
+
and _validate_pre(prereleases)
|
| 1495 |
+
):
|
| 1496 |
+
self._specs = specs
|
| 1497 |
+
self._prereleases = prereleases
|
| 1498 |
+
self._canonicalized = len(self._specs) <= 1
|
| 1499 |
+
self._has_arbitrary = any("===" in str(s) for s in self._specs)
|
| 1500 |
+
return
|
| 1501 |
+
|
| 1502 |
+
raise TypeError(f"Cannot restore SpecifierSet from {state!r}")
|
| 1503 |
+
|
| 1504 |
+
def __repr__(self) -> str:
|
| 1505 |
+
"""A representation of the specifier set that shows all internal state.
|
| 1506 |
+
|
| 1507 |
+
Note that the ordering of the individual specifiers within the set may not
|
| 1508 |
+
match the input string.
|
| 1509 |
+
|
| 1510 |
+
>>> SpecifierSet('>=1.0.0,!=2.0.0')
|
| 1511 |
+
<SpecifierSet('!=2.0.0,>=1.0.0')>
|
| 1512 |
+
>>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=False)
|
| 1513 |
+
<SpecifierSet('!=2.0.0,>=1.0.0', prereleases=False)>
|
| 1514 |
+
>>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=True)
|
| 1515 |
+
<SpecifierSet('!=2.0.0,>=1.0.0', prereleases=True)>
|
| 1516 |
+
"""
|
| 1517 |
+
pre = (
|
| 1518 |
+
f", prereleases={self.prereleases!r}"
|
| 1519 |
+
if self._prereleases is not None
|
| 1520 |
+
else ""
|
| 1521 |
+
)
|
| 1522 |
+
|
| 1523 |
+
return f"<{self.__class__.__name__}({str(self)!r}{pre})>"
|
| 1524 |
+
|
| 1525 |
+
def __str__(self) -> str:
|
| 1526 |
+
"""A string representation of the specifier set that can be round-tripped.
|
| 1527 |
+
|
| 1528 |
+
Note that the ordering of the individual specifiers within the set may not
|
| 1529 |
+
match the input string.
|
| 1530 |
+
|
| 1531 |
+
>>> str(SpecifierSet(">=1.0.0,!=1.0.1"))
|
| 1532 |
+
'!=1.0.1,>=1.0.0'
|
| 1533 |
+
>>> str(SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False))
|
| 1534 |
+
'!=1.0.1,>=1.0.0'
|
| 1535 |
+
"""
|
| 1536 |
+
return ",".join(str(s) for s in self._canonical_specs())
|
| 1537 |
+
|
| 1538 |
+
def __hash__(self) -> int:
|
| 1539 |
+
return hash(self._canonical_specs())
|
| 1540 |
+
|
| 1541 |
+
def __and__(self, other: SpecifierSet | str) -> SpecifierSet:
|
| 1542 |
+
"""Return a SpecifierSet which is a combination of the two sets.
|
| 1543 |
+
|
| 1544 |
+
:param other: The other object to combine with.
|
| 1545 |
+
|
| 1546 |
+
>>> SpecifierSet(">=1.0.0,!=1.0.1") & '<=2.0.0,!=2.0.1'
|
| 1547 |
+
<SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0')>
|
| 1548 |
+
>>> SpecifierSet(">=1.0.0,!=1.0.1") & SpecifierSet('<=2.0.0,!=2.0.1')
|
| 1549 |
+
<SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0')>
|
| 1550 |
+
"""
|
| 1551 |
+
if isinstance(other, str):
|
| 1552 |
+
other = SpecifierSet(other)
|
| 1553 |
+
elif not isinstance(other, SpecifierSet):
|
| 1554 |
+
return NotImplemented
|
| 1555 |
+
|
| 1556 |
+
specifier = SpecifierSet()
|
| 1557 |
+
specifier._specs = self._specs + other._specs
|
| 1558 |
+
specifier._canonicalized = len(specifier._specs) <= 1
|
| 1559 |
+
specifier._has_arbitrary = self._has_arbitrary or other._has_arbitrary
|
| 1560 |
+
specifier._resolved_ops = None
|
| 1561 |
+
|
| 1562 |
+
# Combine prerelease settings: use common or non-None value
|
| 1563 |
+
if self._prereleases is None or self._prereleases == other._prereleases:
|
| 1564 |
+
specifier._prereleases = other._prereleases
|
| 1565 |
+
elif other._prereleases is None:
|
| 1566 |
+
specifier._prereleases = self._prereleases
|
| 1567 |
+
else:
|
| 1568 |
+
raise ValueError(
|
| 1569 |
+
"Cannot combine SpecifierSets with True and False prerelease overrides."
|
| 1570 |
+
)
|
| 1571 |
+
|
| 1572 |
+
return specifier
|
| 1573 |
+
|
| 1574 |
+
def __eq__(self, other: object) -> bool:
|
| 1575 |
+
"""Whether or not the two SpecifierSet-like objects are equal.
|
| 1576 |
+
|
| 1577 |
+
:param other: The other object to check against.
|
| 1578 |
+
|
| 1579 |
+
The value of :attr:`prereleases` is ignored.
|
| 1580 |
+
|
| 1581 |
+
>>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.1")
|
| 1582 |
+
True
|
| 1583 |
+
>>> (SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False) ==
|
| 1584 |
+
... SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True))
|
| 1585 |
+
True
|
| 1586 |
+
>>> SpecifierSet(">=1.0.0,!=1.0.1") == ">=1.0.0,!=1.0.1"
|
| 1587 |
+
True
|
| 1588 |
+
>>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0")
|
| 1589 |
+
False
|
| 1590 |
+
>>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.2")
|
| 1591 |
+
False
|
| 1592 |
+
"""
|
| 1593 |
+
if isinstance(other, (str, Specifier)):
|
| 1594 |
+
other = SpecifierSet(str(other))
|
| 1595 |
+
elif not isinstance(other, SpecifierSet):
|
| 1596 |
+
return NotImplemented
|
| 1597 |
+
|
| 1598 |
+
return self._canonical_specs() == other._canonical_specs()
|
| 1599 |
+
|
| 1600 |
+
def __len__(self) -> int:
|
| 1601 |
+
"""Returns the number of specifiers in this specifier set."""
|
| 1602 |
+
return len(self._specs)
|
| 1603 |
+
|
| 1604 |
+
def __iter__(self) -> Iterator[Specifier]:
|
| 1605 |
+
"""
|
| 1606 |
+
Returns an iterator over all the underlying :class:`Specifier` instances
|
| 1607 |
+
in this specifier set.
|
| 1608 |
+
|
| 1609 |
+
>>> sorted(SpecifierSet(">=1.0.0,!=1.0.1"), key=str)
|
| 1610 |
+
[<Specifier('!=1.0.1')>, <Specifier('>=1.0.0')>]
|
| 1611 |
+
"""
|
| 1612 |
+
return iter(self._specs)
|
| 1613 |
+
|
| 1614 |
+
def _get_ranges(self) -> Sequence[_VersionRange]:
|
| 1615 |
+
"""Intersect all specifiers into a single list of version ranges.
|
| 1616 |
+
|
| 1617 |
+
Returns an empty list when unsatisfiable. ``===`` specs are
|
| 1618 |
+
modeled as full range; string matching is checked separately
|
| 1619 |
+
by :meth:`_check_arbitrary_unsatisfiable`.
|
| 1620 |
+
"""
|
| 1621 |
+
specs = self._specs
|
| 1622 |
+
|
| 1623 |
+
result: Sequence[_VersionRange] | None = None
|
| 1624 |
+
for s in specs:
|
| 1625 |
+
if result is None:
|
| 1626 |
+
result = s._to_ranges()
|
| 1627 |
+
else:
|
| 1628 |
+
result = _intersect_ranges(result, s._to_ranges())
|
| 1629 |
+
if not result:
|
| 1630 |
+
break
|
| 1631 |
+
|
| 1632 |
+
if result is None: # pragma: no cover
|
| 1633 |
+
raise RuntimeError("_get_ranges called with no specs")
|
| 1634 |
+
return result
|
| 1635 |
+
|
| 1636 |
+
def is_unsatisfiable(self) -> bool:
|
| 1637 |
+
"""Check whether this specifier set can never be satisfied.
|
| 1638 |
+
|
| 1639 |
+
Returns True if no version can satisfy all specifiers simultaneously.
|
| 1640 |
+
|
| 1641 |
+
>>> SpecifierSet(">=2.0,<1.0").is_unsatisfiable()
|
| 1642 |
+
True
|
| 1643 |
+
>>> SpecifierSet(">=1.0,<2.0").is_unsatisfiable()
|
| 1644 |
+
False
|
| 1645 |
+
>>> SpecifierSet("").is_unsatisfiable()
|
| 1646 |
+
False
|
| 1647 |
+
>>> SpecifierSet("==1.0,!=1.0").is_unsatisfiable()
|
| 1648 |
+
True
|
| 1649 |
+
"""
|
| 1650 |
+
cached = self._is_unsatisfiable
|
| 1651 |
+
if cached is not None:
|
| 1652 |
+
return cached
|
| 1653 |
+
|
| 1654 |
+
if not self._specs:
|
| 1655 |
+
self._is_unsatisfiable = False
|
| 1656 |
+
return False
|
| 1657 |
+
|
| 1658 |
+
result = not self._get_ranges()
|
| 1659 |
+
|
| 1660 |
+
if not result:
|
| 1661 |
+
result = self._check_arbitrary_unsatisfiable()
|
| 1662 |
+
|
| 1663 |
+
if not result and self.prereleases is False:
|
| 1664 |
+
result = self._check_prerelease_only_ranges()
|
| 1665 |
+
|
| 1666 |
+
self._is_unsatisfiable = result
|
| 1667 |
+
return result
|
| 1668 |
+
|
| 1669 |
+
def _check_prerelease_only_ranges(self) -> bool:
|
| 1670 |
+
"""With prereleases=False, check if every range contains only
|
| 1671 |
+
pre-release versions (which would be excluded from matching)."""
|
| 1672 |
+
for lower, upper in self._get_ranges():
|
| 1673 |
+
nearest = _nearest_non_prerelease(lower.version)
|
| 1674 |
+
if nearest is None:
|
| 1675 |
+
return False
|
| 1676 |
+
if upper.version is None or nearest < upper.version:
|
| 1677 |
+
return False
|
| 1678 |
+
if nearest == upper.version and upper.inclusive:
|
| 1679 |
+
return False
|
| 1680 |
+
return True
|
| 1681 |
+
|
| 1682 |
+
def _check_arbitrary_unsatisfiable(self) -> bool:
|
| 1683 |
+
"""Check === (arbitrary equality) specs for unsatisfiability.
|
| 1684 |
+
|
| 1685 |
+
=== uses case-insensitive string comparison, so the only candidate
|
| 1686 |
+
that can match ``===V`` is the literal string V. This method
|
| 1687 |
+
checks whether that candidate is excluded by other specifiers.
|
| 1688 |
+
"""
|
| 1689 |
+
arbitrary = [s for s in self._specs if s.operator == "==="]
|
| 1690 |
+
if not arbitrary:
|
| 1691 |
+
return False
|
| 1692 |
+
|
| 1693 |
+
# Multiple === must agree on the same string (case-insensitive).
|
| 1694 |
+
first = arbitrary[0].version.lower()
|
| 1695 |
+
if any(s.version.lower() != first for s in arbitrary[1:]):
|
| 1696 |
+
return True
|
| 1697 |
+
|
| 1698 |
+
# The sole candidate is the === version string. Check whether
|
| 1699 |
+
# it can satisfy every standard spec.
|
| 1700 |
+
candidate = _coerce_version(arbitrary[0].version)
|
| 1701 |
+
|
| 1702 |
+
# With prereleases=False, a prerelease candidate is excluded
|
| 1703 |
+
# by contains() before the === string check even runs.
|
| 1704 |
+
if (
|
| 1705 |
+
self.prereleases is False
|
| 1706 |
+
and candidate is not None
|
| 1707 |
+
and candidate.is_prerelease
|
| 1708 |
+
):
|
| 1709 |
+
return True
|
| 1710 |
+
|
| 1711 |
+
standard = [s for s in self._specs if s.operator != "==="]
|
| 1712 |
+
if not standard:
|
| 1713 |
+
return False
|
| 1714 |
+
|
| 1715 |
+
if candidate is None:
|
| 1716 |
+
# Unparsable string cannot satisfy any standard spec.
|
| 1717 |
+
return True
|
| 1718 |
+
|
| 1719 |
+
return not all(s.contains(candidate) for s in standard)
|
| 1720 |
+
|
| 1721 |
+
def __contains__(self, item: UnparsedVersion) -> bool:
|
| 1722 |
+
"""Return whether or not the item is contained in this specifier.
|
| 1723 |
+
|
| 1724 |
+
:param item: The item to check for.
|
| 1725 |
+
|
| 1726 |
+
This is used for the ``in`` operator and behaves the same as
|
| 1727 |
+
:meth:`contains` with no ``prereleases`` argument passed.
|
| 1728 |
+
|
| 1729 |
+
>>> "1.2.3" in SpecifierSet(">=1.0.0,!=1.0.1")
|
| 1730 |
+
True
|
| 1731 |
+
>>> Version("1.2.3") in SpecifierSet(">=1.0.0,!=1.0.1")
|
| 1732 |
+
True
|
| 1733 |
+
>>> "1.0.1" in SpecifierSet(">=1.0.0,!=1.0.1")
|
| 1734 |
+
False
|
| 1735 |
+
>>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1")
|
| 1736 |
+
True
|
| 1737 |
+
>>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True)
|
| 1738 |
+
True
|
| 1739 |
+
"""
|
| 1740 |
+
return self.contains(item)
|
| 1741 |
+
|
| 1742 |
+
def contains(
|
| 1743 |
+
self,
|
| 1744 |
+
item: UnparsedVersion,
|
| 1745 |
+
prereleases: bool | None = None,
|
| 1746 |
+
installed: bool | None = None,
|
| 1747 |
+
) -> bool:
|
| 1748 |
+
"""Return whether or not the item is contained in this SpecifierSet.
|
| 1749 |
+
|
| 1750 |
+
:param item:
|
| 1751 |
+
The item to check for, which can be a version string or a
|
| 1752 |
+
:class:`Version` instance.
|
| 1753 |
+
:param prereleases:
|
| 1754 |
+
Whether or not to match prereleases with this SpecifierSet. If set to
|
| 1755 |
+
``None`` (the default), it will follow the recommendation from :pep:`440`
|
| 1756 |
+
and match prereleases, as there are no other versions.
|
| 1757 |
+
:param installed:
|
| 1758 |
+
Whether or not the item is installed. If set to ``True``, it will
|
| 1759 |
+
accept prerelease versions even if the specifier does not allow them.
|
| 1760 |
+
|
| 1761 |
+
>>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.2.3")
|
| 1762 |
+
True
|
| 1763 |
+
>>> SpecifierSet(">=1.0.0,!=1.0.1").contains(Version("1.2.3"))
|
| 1764 |
+
True
|
| 1765 |
+
>>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.0.1")
|
| 1766 |
+
False
|
| 1767 |
+
>>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1")
|
| 1768 |
+
True
|
| 1769 |
+
>>> SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False).contains("1.3.0a1")
|
| 1770 |
+
False
|
| 1771 |
+
>>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1", prereleases=True)
|
| 1772 |
+
True
|
| 1773 |
+
"""
|
| 1774 |
+
version = _coerce_version(item)
|
| 1775 |
+
|
| 1776 |
+
if version is not None and installed and version.is_prerelease:
|
| 1777 |
+
prereleases = True
|
| 1778 |
+
|
| 1779 |
+
# When item is a string and === is involved, keep it as-is
|
| 1780 |
+
# so the comparison isn't done against the normalized form.
|
| 1781 |
+
if version is None or (self._has_arbitrary and not isinstance(item, Version)):
|
| 1782 |
+
check_item = item
|
| 1783 |
+
else:
|
| 1784 |
+
check_item = version
|
| 1785 |
+
return bool(list(self.filter([check_item], prereleases=prereleases)))
|
| 1786 |
+
|
| 1787 |
+
@typing.overload
|
| 1788 |
+
def filter(
|
| 1789 |
+
self,
|
| 1790 |
+
iterable: Iterable[UnparsedVersionVar],
|
| 1791 |
+
prereleases: bool | None = None,
|
| 1792 |
+
key: None = ...,
|
| 1793 |
+
) -> Iterator[UnparsedVersionVar]: ...
|
| 1794 |
+
|
| 1795 |
+
@typing.overload
|
| 1796 |
+
def filter(
|
| 1797 |
+
self,
|
| 1798 |
+
iterable: Iterable[T],
|
| 1799 |
+
prereleases: bool | None = None,
|
| 1800 |
+
key: Callable[[T], UnparsedVersion] = ...,
|
| 1801 |
+
) -> Iterator[T]: ...
|
| 1802 |
+
|
| 1803 |
+
def filter(
|
| 1804 |
+
self,
|
| 1805 |
+
iterable: Iterable[Any],
|
| 1806 |
+
prereleases: bool | None = None,
|
| 1807 |
+
key: Callable[[Any], UnparsedVersion] | None = None,
|
| 1808 |
+
) -> Iterator[Any]:
|
| 1809 |
+
"""Filter items in the given iterable, that match the specifiers in this set.
|
| 1810 |
+
|
| 1811 |
+
:param iterable:
|
| 1812 |
+
An iterable that can contain version strings and :class:`Version` instances.
|
| 1813 |
+
The items in the iterable will be filtered according to the specifier.
|
| 1814 |
+
:param prereleases:
|
| 1815 |
+
Whether or not to allow prereleases in the returned iterator. If set to
|
| 1816 |
+
``None`` (the default), it will follow the recommendation from :pep:`440`
|
| 1817 |
+
and match prereleases if there are no other versions.
|
| 1818 |
+
:param key:
|
| 1819 |
+
A callable that takes a single argument (an item from the iterable) and
|
| 1820 |
+
returns a version string or :class:`Version` instance to be used for
|
| 1821 |
+
filtering.
|
| 1822 |
+
|
| 1823 |
+
>>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", "1.5a1"]))
|
| 1824 |
+
['1.3']
|
| 1825 |
+
>>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", Version("1.4")]))
|
| 1826 |
+
['1.3', <Version('1.4')>]
|
| 1827 |
+
>>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.5a1"]))
|
| 1828 |
+
['1.5a1']
|
| 1829 |
+
>>> list(SpecifierSet(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True))
|
| 1830 |
+
['1.3', '1.5a1']
|
| 1831 |
+
>>> list(SpecifierSet(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"]))
|
| 1832 |
+
['1.3', '1.5a1']
|
| 1833 |
+
>>> list(SpecifierSet(">=1.2.3").filter(
|
| 1834 |
+
... [{"ver": "1.2"}, {"ver": "1.3"}],
|
| 1835 |
+
... key=lambda x: x["ver"]))
|
| 1836 |
+
[{'ver': '1.3'}]
|
| 1837 |
+
|
| 1838 |
+
An "empty" SpecifierSet will filter items based on the presence of prerelease
|
| 1839 |
+
versions in the set.
|
| 1840 |
+
|
| 1841 |
+
>>> list(SpecifierSet("").filter(["1.3", "1.5a1"]))
|
| 1842 |
+
['1.3']
|
| 1843 |
+
>>> list(SpecifierSet("").filter(["1.5a1"]))
|
| 1844 |
+
['1.5a1']
|
| 1845 |
+
>>> list(SpecifierSet("", prereleases=True).filter(["1.3", "1.5a1"]))
|
| 1846 |
+
['1.3', '1.5a1']
|
| 1847 |
+
>>> list(SpecifierSet("").filter(["1.3", "1.5a1"], prereleases=True))
|
| 1848 |
+
['1.3', '1.5a1']
|
| 1849 |
+
"""
|
| 1850 |
+
# Determine if we're forcing a prerelease or not, if we're not forcing
|
| 1851 |
+
# one for this particular filter call, then we'll use whatever the
|
| 1852 |
+
# SpecifierSet thinks for whether or not we should support prereleases.
|
| 1853 |
+
if prereleases is None and self.prereleases is not None:
|
| 1854 |
+
prereleases = self.prereleases
|
| 1855 |
+
|
| 1856 |
+
# Filter versions that match all specifiers using Cost Based Ordering.
|
| 1857 |
+
if self._specs:
|
| 1858 |
+
# When prereleases is None, we need to let all versions through
|
| 1859 |
+
# the individual filters, then decide about prereleases at the end
|
| 1860 |
+
# based on whether any non-prereleases matched ALL specs.
|
| 1861 |
+
|
| 1862 |
+
# Fast path: single specifier, delegate directly.
|
| 1863 |
+
if len(self._specs) == 1:
|
| 1864 |
+
filtered = self._specs[0].filter(
|
| 1865 |
+
iterable,
|
| 1866 |
+
prereleases=True if prereleases is None else prereleases,
|
| 1867 |
+
key=key,
|
| 1868 |
+
)
|
| 1869 |
+
else:
|
| 1870 |
+
filtered = self._filter_versions(
|
| 1871 |
+
iterable,
|
| 1872 |
+
key,
|
| 1873 |
+
prereleases=True if prereleases is None else prereleases,
|
| 1874 |
+
)
|
| 1875 |
+
|
| 1876 |
+
if prereleases is not None:
|
| 1877 |
+
return filtered
|
| 1878 |
+
|
| 1879 |
+
return _pep440_filter_prereleases(filtered, key)
|
| 1880 |
+
|
| 1881 |
+
# Handle Empty SpecifierSet.
|
| 1882 |
+
if prereleases is True:
|
| 1883 |
+
return iter(iterable)
|
| 1884 |
+
|
| 1885 |
+
if prereleases is False:
|
| 1886 |
+
return (
|
| 1887 |
+
item
|
| 1888 |
+
for item in iterable
|
| 1889 |
+
if (
|
| 1890 |
+
(version := _coerce_version(item if key is None else key(item)))
|
| 1891 |
+
is None
|
| 1892 |
+
or not version.is_prerelease
|
| 1893 |
+
)
|
| 1894 |
+
)
|
| 1895 |
+
|
| 1896 |
+
# PEP 440: exclude prereleases unless no final releases matched
|
| 1897 |
+
return _pep440_filter_prereleases(iterable, key)
|
| 1898 |
+
|
| 1899 |
+
def _filter_versions(
|
| 1900 |
+
self,
|
| 1901 |
+
iterable: Iterable[Any],
|
| 1902 |
+
key: Callable[[Any], UnparsedVersion] | None,
|
| 1903 |
+
prereleases: bool | None = None,
|
| 1904 |
+
) -> Iterator[Any]:
|
| 1905 |
+
"""Filter versions against all specifiers in a single pass.
|
| 1906 |
+
|
| 1907 |
+
Uses Cost Based Ordering: specifiers are sorted by _operator_cost so
|
| 1908 |
+
that cheap range operators reject versions early, avoiding expensive
|
| 1909 |
+
wildcard or compatible operators on versions that would have been
|
| 1910 |
+
rejected anyway.
|
| 1911 |
+
"""
|
| 1912 |
+
# Pre-resolve operators and sort (cached after first call).
|
| 1913 |
+
if self._resolved_ops is None:
|
| 1914 |
+
self._resolved_ops = sorted(
|
| 1915 |
+
(
|
| 1916 |
+
(spec._get_operator(spec.operator), spec.version, spec.operator)
|
| 1917 |
+
for spec in self._specs
|
| 1918 |
+
),
|
| 1919 |
+
key=_operator_cost,
|
| 1920 |
+
)
|
| 1921 |
+
ops = self._resolved_ops
|
| 1922 |
+
exclude_prereleases = prereleases is False
|
| 1923 |
+
|
| 1924 |
+
for item in iterable:
|
| 1925 |
+
parsed = _coerce_version(item if key is None else key(item))
|
| 1926 |
+
|
| 1927 |
+
if parsed is None:
|
| 1928 |
+
# Only === can match non-parseable versions.
|
| 1929 |
+
if all(
|
| 1930 |
+
op == "===" and str(item).lower() == ver.lower()
|
| 1931 |
+
for _, ver, op in ops
|
| 1932 |
+
):
|
| 1933 |
+
yield item
|
| 1934 |
+
elif exclude_prereleases and parsed.is_prerelease:
|
| 1935 |
+
pass
|
| 1936 |
+
elif all(
|
| 1937 |
+
str(item if key is None else key(item)).lower() == ver.lower()
|
| 1938 |
+
if op == "==="
|
| 1939 |
+
else op_fn(parsed, ver)
|
| 1940 |
+
for op_fn, ver, op in ops
|
| 1941 |
+
):
|
| 1942 |
+
# Short-circuits on the first failing operator.
|
| 1943 |
+
yield item
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/tags.py
ADDED
|
@@ -0,0 +1,932 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
|
| 5 |
+
from __future__ import annotations
|
| 6 |
+
|
| 7 |
+
import logging
|
| 8 |
+
import operator
|
| 9 |
+
import platform
|
| 10 |
+
import re
|
| 11 |
+
import struct
|
| 12 |
+
import subprocess
|
| 13 |
+
import sys
|
| 14 |
+
import sysconfig
|
| 15 |
+
from importlib.machinery import EXTENSION_SUFFIXES
|
| 16 |
+
from typing import (
|
| 17 |
+
TYPE_CHECKING,
|
| 18 |
+
Iterable,
|
| 19 |
+
Iterator,
|
| 20 |
+
Sequence,
|
| 21 |
+
Tuple,
|
| 22 |
+
TypeVar,
|
| 23 |
+
cast,
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
from . import _manylinux, _musllinux
|
| 27 |
+
|
| 28 |
+
if TYPE_CHECKING:
|
| 29 |
+
from collections.abc import Callable, Iterable
|
| 30 |
+
from typing import AbstractSet
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
__all__ = [
|
| 34 |
+
"INTERPRETER_SHORT_NAMES",
|
| 35 |
+
"AppleVersion",
|
| 36 |
+
"PythonVersion",
|
| 37 |
+
"Tag",
|
| 38 |
+
"UnsortedTagsError",
|
| 39 |
+
"android_platforms",
|
| 40 |
+
"compatible_tags",
|
| 41 |
+
"cpython_tags",
|
| 42 |
+
"create_compatible_tags_selector",
|
| 43 |
+
"generic_tags",
|
| 44 |
+
"interpreter_name",
|
| 45 |
+
"interpreter_version",
|
| 46 |
+
"ios_platforms",
|
| 47 |
+
"mac_platforms",
|
| 48 |
+
"parse_tag",
|
| 49 |
+
"platform_tags",
|
| 50 |
+
"sys_tags",
|
| 51 |
+
]
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def __dir__() -> list[str]:
|
| 55 |
+
return __all__
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
logger = logging.getLogger(__name__)
|
| 59 |
+
|
| 60 |
+
PythonVersion = Sequence[int]
|
| 61 |
+
AppleVersion = Tuple[int, int]
|
| 62 |
+
_T = TypeVar("_T")
|
| 63 |
+
|
| 64 |
+
INTERPRETER_SHORT_NAMES: dict[str, str] = {
|
| 65 |
+
"python": "py", # Generic.
|
| 66 |
+
"cpython": "cp",
|
| 67 |
+
"pypy": "pp",
|
| 68 |
+
"ironpython": "ip",
|
| 69 |
+
"jython": "jy",
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
# This function can be unit tested without reloading the module
|
| 74 |
+
# (Unlike _32_BIT_INTERPRETER)
|
| 75 |
+
def _compute_32_bit_interpreter() -> bool:
|
| 76 |
+
return struct.calcsize("P") == 4
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
_32_BIT_INTERPRETER = _compute_32_bit_interpreter()
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
class UnsortedTagsError(ValueError):
|
| 83 |
+
"""
|
| 84 |
+
Raised when a tag component is not in sorted order per PEP 425.
|
| 85 |
+
"""
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
class Tag:
|
| 89 |
+
"""
|
| 90 |
+
A representation of the tag triple for a wheel.
|
| 91 |
+
|
| 92 |
+
Instances are considered immutable and thus are hashable. Equality checking
|
| 93 |
+
is also supported.
|
| 94 |
+
|
| 95 |
+
Instances are safe to serialize with :mod:`pickle`. They use a stable
|
| 96 |
+
format so the same pickle can be loaded in future packaging releases.
|
| 97 |
+
|
| 98 |
+
.. versionchanged:: 26.2
|
| 99 |
+
|
| 100 |
+
Added a stable pickle format. Pickles created with packaging 26.2+ can
|
| 101 |
+
be unpickled with future releases. Backward compatibility with pickles
|
| 102 |
+
from pip._vendor.packaging < 26.2 is supported but may be removed in a future
|
| 103 |
+
release.
|
| 104 |
+
"""
|
| 105 |
+
|
| 106 |
+
__slots__ = ["_abi", "_hash", "_interpreter", "_platform"]
|
| 107 |
+
|
| 108 |
+
def __init__(self, interpreter: str, abi: str, platform: str) -> None:
|
| 109 |
+
"""
|
| 110 |
+
:param str interpreter: The interpreter name, e.g. ``"py"``
|
| 111 |
+
(see :attr:`INTERPRETER_SHORT_NAMES` for mapping
|
| 112 |
+
well-known interpreter names to their short names).
|
| 113 |
+
:param str abi: The ABI that a wheel supports, e.g. ``"cp37m"``.
|
| 114 |
+
:param str platform: The OS/platform the wheel supports,
|
| 115 |
+
e.g. ``"win_amd64"``.
|
| 116 |
+
"""
|
| 117 |
+
self._interpreter = interpreter.lower()
|
| 118 |
+
self._abi = abi.lower()
|
| 119 |
+
self._platform = platform.lower()
|
| 120 |
+
# The __hash__ of every single element in a Set[Tag] will be evaluated each time
|
| 121 |
+
# that a set calls its `.disjoint()` method, which may be called hundreds of
|
| 122 |
+
# times when scanning a page of links for packages with tags matching that
|
| 123 |
+
# Set[Tag]. Pre-computing the value here produces significant speedups for
|
| 124 |
+
# downstream consumers.
|
| 125 |
+
self._hash = hash((self._interpreter, self._abi, self._platform))
|
| 126 |
+
|
| 127 |
+
@property
|
| 128 |
+
def interpreter(self) -> str:
|
| 129 |
+
"""
|
| 130 |
+
The interpreter name, e.g. ``"py"`` (see
|
| 131 |
+
:attr:`INTERPRETER_SHORT_NAMES` for mapping well-known interpreter
|
| 132 |
+
names to their short names).
|
| 133 |
+
"""
|
| 134 |
+
return self._interpreter
|
| 135 |
+
|
| 136 |
+
@property
|
| 137 |
+
def abi(self) -> str:
|
| 138 |
+
"""
|
| 139 |
+
The supported ABI.
|
| 140 |
+
"""
|
| 141 |
+
return self._abi
|
| 142 |
+
|
| 143 |
+
@property
|
| 144 |
+
def platform(self) -> str:
|
| 145 |
+
"""
|
| 146 |
+
The OS/platform.
|
| 147 |
+
"""
|
| 148 |
+
return self._platform
|
| 149 |
+
|
| 150 |
+
def __eq__(self, other: object) -> bool:
|
| 151 |
+
if not isinstance(other, Tag):
|
| 152 |
+
return NotImplemented
|
| 153 |
+
|
| 154 |
+
return (
|
| 155 |
+
(self._hash == other._hash) # Short-circuit ASAP for perf reasons.
|
| 156 |
+
and (self._platform == other._platform)
|
| 157 |
+
and (self._abi == other._abi)
|
| 158 |
+
and (self._interpreter == other._interpreter)
|
| 159 |
+
)
|
| 160 |
+
|
| 161 |
+
def __hash__(self) -> int:
|
| 162 |
+
return self._hash
|
| 163 |
+
|
| 164 |
+
def __str__(self) -> str:
|
| 165 |
+
return f"{self._interpreter}-{self._abi}-{self._platform}"
|
| 166 |
+
|
| 167 |
+
def __repr__(self) -> str:
|
| 168 |
+
return f"<{self} @ {id(self)}>"
|
| 169 |
+
|
| 170 |
+
def __getstate__(self) -> tuple[str, str, str]:
|
| 171 |
+
# Return state as a 3-item tuple: (interpreter, abi, platform).
|
| 172 |
+
# Cache member _hash is excluded and will be recomputed.
|
| 173 |
+
return (self._interpreter, self._abi, self._platform)
|
| 174 |
+
|
| 175 |
+
def __setstate__(self, state: object) -> None:
|
| 176 |
+
if isinstance(state, tuple):
|
| 177 |
+
if len(state) == 3 and all(isinstance(s, str) for s in state):
|
| 178 |
+
# New format (26.2+): (interpreter, abi, platform)
|
| 179 |
+
self._interpreter, self._abi, self._platform = state
|
| 180 |
+
self._hash = hash((self._interpreter, self._abi, self._platform))
|
| 181 |
+
return
|
| 182 |
+
if len(state) == 2 and isinstance(state[1], dict):
|
| 183 |
+
# Old format (packaging <= 26.1, __slots__): (None, {slot: value}).
|
| 184 |
+
_, slots = state
|
| 185 |
+
try:
|
| 186 |
+
interpreter = slots["_interpreter"]
|
| 187 |
+
abi = slots["_abi"]
|
| 188 |
+
platform = slots["_platform"]
|
| 189 |
+
except KeyError:
|
| 190 |
+
raise TypeError(f"Cannot restore Tag from {state!r}") from None
|
| 191 |
+
if not all(
|
| 192 |
+
isinstance(value, str) for value in (interpreter, abi, platform)
|
| 193 |
+
):
|
| 194 |
+
raise TypeError(f"Cannot restore Tag from {state!r}")
|
| 195 |
+
self._interpreter = interpreter.lower()
|
| 196 |
+
self._abi = abi.lower()
|
| 197 |
+
self._platform = platform.lower()
|
| 198 |
+
self._hash = hash((self._interpreter, self._abi, self._platform))
|
| 199 |
+
return
|
| 200 |
+
raise TypeError(f"Cannot restore Tag from {state!r}")
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
def parse_tag(tag: str, *, validate_order: bool = False) -> frozenset[Tag]:
|
| 204 |
+
"""
|
| 205 |
+
Parses the provided tag (e.g. `py3-none-any`) into a frozenset of
|
| 206 |
+
:class:`Tag` instances.
|
| 207 |
+
|
| 208 |
+
Returning a set is required due to the possibility that the tag is a
|
| 209 |
+
`compressed tag set`_, e.g. ``"py2.py3-none-any"`` which supports both
|
| 210 |
+
Python 2 and Python 3.
|
| 211 |
+
|
| 212 |
+
If **validate_order** is true, compressed tag set components are checked
|
| 213 |
+
to be in sorted order as required by PEP 425.
|
| 214 |
+
|
| 215 |
+
:param str tag: The tag to parse, e.g. ``"py3-none-any"``.
|
| 216 |
+
:param bool validate_order: Check whether compressed tag set components
|
| 217 |
+
are in sorted order.
|
| 218 |
+
:raises UnsortedTagsError: If **validate_order** is true and any compressed tag
|
| 219 |
+
set component is not in sorted order.
|
| 220 |
+
|
| 221 |
+
.. versionadded:: 26.1
|
| 222 |
+
The *validate_order* parameter.
|
| 223 |
+
"""
|
| 224 |
+
tags = set()
|
| 225 |
+
interpreters, abis, platforms = tag.split("-")
|
| 226 |
+
if validate_order:
|
| 227 |
+
for component in (interpreters, abis, platforms):
|
| 228 |
+
parts = component.split(".")
|
| 229 |
+
if parts != sorted(parts):
|
| 230 |
+
raise UnsortedTagsError(
|
| 231 |
+
f"Tag component {component!r} is not in sorted order per PEP 425"
|
| 232 |
+
)
|
| 233 |
+
for interpreter in interpreters.split("."):
|
| 234 |
+
for abi in abis.split("."):
|
| 235 |
+
for platform_ in platforms.split("."):
|
| 236 |
+
tags.add(Tag(interpreter, abi, platform_))
|
| 237 |
+
return frozenset(tags)
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
def _get_config_var(name: str, warn: bool = False) -> int | str | None:
|
| 241 |
+
value: int | str | None = sysconfig.get_config_var(name)
|
| 242 |
+
if value is None and warn:
|
| 243 |
+
logger.debug(
|
| 244 |
+
"Config variable '%s' is unset, Python ABI tag may be incorrect", name
|
| 245 |
+
)
|
| 246 |
+
return value
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
def _normalize_string(string: str) -> str:
|
| 250 |
+
return string.replace(".", "_").replace("-", "_").replace(" ", "_")
|
| 251 |
+
|
| 252 |
+
|
| 253 |
+
def _is_threaded_cpython(abis: list[str]) -> bool:
|
| 254 |
+
"""
|
| 255 |
+
Determine if the ABI corresponds to a threaded (`--disable-gil`) build.
|
| 256 |
+
|
| 257 |
+
The threaded builds are indicated by a "t" in the abiflags.
|
| 258 |
+
"""
|
| 259 |
+
if len(abis) == 0:
|
| 260 |
+
return False
|
| 261 |
+
# expect e.g., cp313
|
| 262 |
+
m = re.match(r"cp\d+(.*)", abis[0])
|
| 263 |
+
if not m:
|
| 264 |
+
return False
|
| 265 |
+
abiflags = m.group(1)
|
| 266 |
+
return "t" in abiflags
|
| 267 |
+
|
| 268 |
+
|
| 269 |
+
def _abi3_applies(python_version: PythonVersion, threading: bool) -> bool:
|
| 270 |
+
"""
|
| 271 |
+
Determine if the Python version supports abi3.
|
| 272 |
+
|
| 273 |
+
PEP 384 was first implemented in Python 3.2. The free-threaded
|
| 274 |
+
builds do not support abi3.
|
| 275 |
+
"""
|
| 276 |
+
return len(python_version) > 1 and tuple(python_version) >= (3, 2) and not threading
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
def _abi3t_applies(python_version: PythonVersion, threading: bool) -> bool:
|
| 280 |
+
"""
|
| 281 |
+
Determine if the Python version supports abi3t.
|
| 282 |
+
|
| 283 |
+
PEP 803 was first implemented in Python 3.15 but, per PEP 803, this
|
| 284 |
+
returns tags going back to Python 3.2 to mirror the abi3
|
| 285 |
+
implementation and leave open the possibility of abi3t wheels
|
| 286 |
+
supporting older Python versions.
|
| 287 |
+
|
| 288 |
+
"""
|
| 289 |
+
return len(python_version) > 1 and tuple(python_version) >= (3, 2) and threading
|
| 290 |
+
|
| 291 |
+
|
| 292 |
+
def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> list[str]:
|
| 293 |
+
py_version = tuple(py_version) # To allow for version comparison.
|
| 294 |
+
abis = []
|
| 295 |
+
version = _version_nodot(py_version[:2])
|
| 296 |
+
threading = debug = pymalloc = ucs4 = ""
|
| 297 |
+
with_debug = _get_config_var("Py_DEBUG", warn)
|
| 298 |
+
has_refcount = hasattr(sys, "gettotalrefcount")
|
| 299 |
+
# Windows doesn't set Py_DEBUG, so checking for support of debug-compiled
|
| 300 |
+
# extension modules is the best option.
|
| 301 |
+
# https://github.com/pypa/pip/issues/3383#issuecomment-173267692
|
| 302 |
+
has_ext = "_d.pyd" in EXTENSION_SUFFIXES
|
| 303 |
+
if with_debug or (with_debug is None and (has_refcount or has_ext)):
|
| 304 |
+
debug = "d"
|
| 305 |
+
if py_version >= (3, 13) and _get_config_var("Py_GIL_DISABLED", warn):
|
| 306 |
+
threading = "t"
|
| 307 |
+
if py_version < (3, 8):
|
| 308 |
+
with_pymalloc = _get_config_var("WITH_PYMALLOC", warn)
|
| 309 |
+
if with_pymalloc or with_pymalloc is None:
|
| 310 |
+
pymalloc = "m"
|
| 311 |
+
if py_version < (3, 3):
|
| 312 |
+
unicode_size = _get_config_var("Py_UNICODE_SIZE", warn)
|
| 313 |
+
if unicode_size == 4 or (
|
| 314 |
+
unicode_size is None and sys.maxunicode == 0x10FFFF
|
| 315 |
+
):
|
| 316 |
+
ucs4 = "u"
|
| 317 |
+
elif debug:
|
| 318 |
+
# Debug builds can also load "normal" extension modules.
|
| 319 |
+
# We can also assume no UCS-4 or pymalloc requirement.
|
| 320 |
+
abis.append(f"cp{version}{threading}")
|
| 321 |
+
abis.insert(0, f"cp{version}{threading}{debug}{pymalloc}{ucs4}")
|
| 322 |
+
return abis
|
| 323 |
+
|
| 324 |
+
|
| 325 |
+
def cpython_tags(
|
| 326 |
+
python_version: PythonVersion | None = None,
|
| 327 |
+
abis: Iterable[str] | None = None,
|
| 328 |
+
platforms: Iterable[str] | None = None,
|
| 329 |
+
*,
|
| 330 |
+
warn: bool = False,
|
| 331 |
+
) -> Iterator[Tag]:
|
| 332 |
+
"""
|
| 333 |
+
Yields the tags for the CPython interpreter.
|
| 334 |
+
|
| 335 |
+
The specific tags generated are:
|
| 336 |
+
|
| 337 |
+
- ``cp<python_version>-<abi>-<platform>``
|
| 338 |
+
- ``cp<python_version>-<stable_abi>-<platform>``
|
| 339 |
+
- ``cp<python_version>-none-<platform>``
|
| 340 |
+
- ``cp<older version>-<stable_abi>-<platform>`` where "older version" is all older
|
| 341 |
+
minor versions down to Python 3.2 (when ``abi3`` was introduced)
|
| 342 |
+
|
| 343 |
+
If ``python_version`` only provides a major-only version then only
|
| 344 |
+
user-provided ABIs via ``abis`` and the ``none`` ABI will be used.
|
| 345 |
+
|
| 346 |
+
The ``stable_abi`` will be either ``abi3`` or ``abi3t`` if `abi` is a
|
| 347 |
+
GIL-enabled ABI like `"cp315"` or a free-threaded ABI like `"cp315t"`,
|
| 348 |
+
respectively.
|
| 349 |
+
|
| 350 |
+
:param Sequence python_version: A one- or two-item sequence representing the
|
| 351 |
+
targeted Python version. Defaults to
|
| 352 |
+
``sys.version_info[:2]``.
|
| 353 |
+
:param Iterable abis: Iterable of compatible ABIs. Defaults to the ABIs
|
| 354 |
+
compatible with the current system.
|
| 355 |
+
:param Iterable platforms: Iterable of compatible platforms. Defaults to the
|
| 356 |
+
platforms compatible with the current system.
|
| 357 |
+
:param bool warn: Whether warnings should be logged. Defaults to ``False``.
|
| 358 |
+
"""
|
| 359 |
+
if not python_version:
|
| 360 |
+
python_version = sys.version_info[:2]
|
| 361 |
+
|
| 362 |
+
interpreter = f"cp{_version_nodot(python_version[:2])}"
|
| 363 |
+
|
| 364 |
+
if abis is None:
|
| 365 |
+
abis = _cpython_abis(python_version, warn) if len(python_version) > 1 else []
|
| 366 |
+
abis = list(abis)
|
| 367 |
+
# 'abi3' and 'none' are explicitly handled later.
|
| 368 |
+
for explicit_abi in ("abi3", "none"):
|
| 369 |
+
try:
|
| 370 |
+
abis.remove(explicit_abi)
|
| 371 |
+
except ValueError: # noqa: PERF203
|
| 372 |
+
pass
|
| 373 |
+
|
| 374 |
+
platforms = list(platforms or platform_tags())
|
| 375 |
+
for abi in abis:
|
| 376 |
+
for platform_ in platforms:
|
| 377 |
+
yield Tag(interpreter, abi, platform_)
|
| 378 |
+
|
| 379 |
+
threading = _is_threaded_cpython(abis)
|
| 380 |
+
use_abi3 = _abi3_applies(python_version, threading)
|
| 381 |
+
use_abi3t = _abi3t_applies(python_version, threading)
|
| 382 |
+
|
| 383 |
+
if use_abi3:
|
| 384 |
+
yield from (Tag(interpreter, "abi3", platform_) for platform_ in platforms)
|
| 385 |
+
if use_abi3t:
|
| 386 |
+
yield from (Tag(interpreter, "abi3t", platform_) for platform_ in platforms)
|
| 387 |
+
|
| 388 |
+
yield from (Tag(interpreter, "none", platform_) for platform_ in platforms)
|
| 389 |
+
|
| 390 |
+
if use_abi3 or use_abi3t:
|
| 391 |
+
for minor_version in range(python_version[1] - 1, 1, -1):
|
| 392 |
+
for platform_ in platforms:
|
| 393 |
+
version = _version_nodot((python_version[0], minor_version))
|
| 394 |
+
interpreter = f"cp{version}"
|
| 395 |
+
if use_abi3:
|
| 396 |
+
yield Tag(interpreter, "abi3", platform_)
|
| 397 |
+
if use_abi3t:
|
| 398 |
+
# Support for abi3t was introduced in Python 3.15, but in
|
| 399 |
+
# principle abi3t wheels are possible for older limited API
|
| 400 |
+
# versions, so allow things like ("cp37", "abi3t", "platform")
|
| 401 |
+
yield Tag(interpreter, "abi3t", platform_)
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
def _generic_abi() -> list[str]:
|
| 405 |
+
"""
|
| 406 |
+
Return the ABI tag based on EXT_SUFFIX.
|
| 407 |
+
"""
|
| 408 |
+
# The following are examples of `EXT_SUFFIX`.
|
| 409 |
+
# We want to keep the parts which are related to the ABI and remove the
|
| 410 |
+
# parts which are related to the platform:
|
| 411 |
+
# - linux: '.cpython-310-x86_64-linux-gnu.so' => cp310
|
| 412 |
+
# - mac: '.cpython-310-darwin.so' => cp310
|
| 413 |
+
# - win: '.cp310-win_amd64.pyd' => cp310
|
| 414 |
+
# - win: '.pyd' => cp37 (uses _cpython_abis())
|
| 415 |
+
# - pypy: '.pypy38-pp73-x86_64-linux-gnu.so' => pypy38_pp73
|
| 416 |
+
# - graalpy: '.graalpy-38-native-x86_64-darwin.dylib'
|
| 417 |
+
# => graalpy_38_native
|
| 418 |
+
|
| 419 |
+
ext_suffix = _get_config_var("EXT_SUFFIX", warn=True)
|
| 420 |
+
if not isinstance(ext_suffix, str) or ext_suffix[0] != ".":
|
| 421 |
+
raise SystemError("invalid sysconfig.get_config_var('EXT_SUFFIX')")
|
| 422 |
+
parts = ext_suffix.split(".")
|
| 423 |
+
if len(parts) < 3:
|
| 424 |
+
# CPython3.7 and earlier uses ".pyd" on Windows.
|
| 425 |
+
return _cpython_abis(sys.version_info[:2])
|
| 426 |
+
soabi = parts[1]
|
| 427 |
+
if soabi.startswith("cpython"):
|
| 428 |
+
# non-windows
|
| 429 |
+
abi = "cp" + soabi.split("-")[1]
|
| 430 |
+
elif soabi.startswith("cp"):
|
| 431 |
+
# windows
|
| 432 |
+
abi = soabi.split("-")[0]
|
| 433 |
+
elif soabi.startswith("pypy"):
|
| 434 |
+
abi = "-".join(soabi.split("-")[:2])
|
| 435 |
+
elif soabi.startswith("graalpy"):
|
| 436 |
+
abi = "-".join(soabi.split("-")[:3])
|
| 437 |
+
elif soabi:
|
| 438 |
+
# pyston, ironpython, others?
|
| 439 |
+
abi = soabi
|
| 440 |
+
else:
|
| 441 |
+
return []
|
| 442 |
+
return [_normalize_string(abi)]
|
| 443 |
+
|
| 444 |
+
|
| 445 |
+
def generic_tags(
|
| 446 |
+
interpreter: str | None = None,
|
| 447 |
+
abis: Iterable[str] | None = None,
|
| 448 |
+
platforms: Iterable[str] | None = None,
|
| 449 |
+
*,
|
| 450 |
+
warn: bool = False,
|
| 451 |
+
) -> Iterator[Tag]:
|
| 452 |
+
"""
|
| 453 |
+
Yields the tags for an interpreter which requires no specialization.
|
| 454 |
+
|
| 455 |
+
This function should be used if one of the other interpreter-specific
|
| 456 |
+
functions provided by this module is not appropriate (i.e. not calculating
|
| 457 |
+
tags for a CPython interpreter).
|
| 458 |
+
|
| 459 |
+
The specific tags generated are:
|
| 460 |
+
|
| 461 |
+
- ``<interpreter>-<abi>-<platform>``
|
| 462 |
+
|
| 463 |
+
The ``"none"`` ABI will be added if it was not explicitly provided.
|
| 464 |
+
|
| 465 |
+
:param str interpreter: The name of the interpreter. Defaults to being
|
| 466 |
+
calculated.
|
| 467 |
+
:param Iterable abis: Iterable of compatible ABIs. Defaults to the ABIs
|
| 468 |
+
compatible with the current system.
|
| 469 |
+
:param Iterable platforms: Iterable of compatible platforms. Defaults to the
|
| 470 |
+
platforms compatible with the current system.
|
| 471 |
+
:param bool warn: Whether warnings should be logged. Defaults to ``False``.
|
| 472 |
+
"""
|
| 473 |
+
if not interpreter:
|
| 474 |
+
interp_name = interpreter_name()
|
| 475 |
+
interp_version = interpreter_version(warn=warn)
|
| 476 |
+
interpreter = f"{interp_name}{interp_version}"
|
| 477 |
+
abis = _generic_abi() if abis is None else list(abis)
|
| 478 |
+
platforms = list(platforms or platform_tags())
|
| 479 |
+
if "none" not in abis:
|
| 480 |
+
abis.append("none")
|
| 481 |
+
for abi in abis:
|
| 482 |
+
for platform_ in platforms:
|
| 483 |
+
yield Tag(interpreter, abi, platform_)
|
| 484 |
+
|
| 485 |
+
|
| 486 |
+
def _py_interpreter_range(py_version: PythonVersion) -> Iterator[str]:
|
| 487 |
+
"""
|
| 488 |
+
Yields Python versions in descending order.
|
| 489 |
+
|
| 490 |
+
After the latest version, the major-only version will be yielded, and then
|
| 491 |
+
all previous versions of that major version.
|
| 492 |
+
"""
|
| 493 |
+
if len(py_version) > 1:
|
| 494 |
+
yield f"py{_version_nodot(py_version[:2])}"
|
| 495 |
+
yield f"py{py_version[0]}"
|
| 496 |
+
if len(py_version) > 1:
|
| 497 |
+
for minor in range(py_version[1] - 1, -1, -1):
|
| 498 |
+
yield f"py{_version_nodot((py_version[0], minor))}"
|
| 499 |
+
|
| 500 |
+
|
| 501 |
+
def compatible_tags(
|
| 502 |
+
python_version: PythonVersion | None = None,
|
| 503 |
+
interpreter: str | None = None,
|
| 504 |
+
platforms: Iterable[str] | None = None,
|
| 505 |
+
) -> Iterator[Tag]:
|
| 506 |
+
"""
|
| 507 |
+
Yields the tags for an interpreter compatible with the Python version
|
| 508 |
+
specified by ``python_version``.
|
| 509 |
+
|
| 510 |
+
The specific tags generated are:
|
| 511 |
+
|
| 512 |
+
- ``py*-none-<platform>``
|
| 513 |
+
- ``<interpreter>-none-any`` if ``interpreter`` is provided
|
| 514 |
+
- ``py*-none-any``
|
| 515 |
+
|
| 516 |
+
:param Sequence python_version: A one- or two-item sequence representing the
|
| 517 |
+
compatible version of Python. Defaults to
|
| 518 |
+
``sys.version_info[:2]``.
|
| 519 |
+
:param str interpreter: The name of the interpreter (if known), e.g.
|
| 520 |
+
``"cp38"``. Defaults to the current interpreter.
|
| 521 |
+
:param Iterable platforms: Iterable of compatible platforms. Defaults to the
|
| 522 |
+
platforms compatible with the current system.
|
| 523 |
+
"""
|
| 524 |
+
if not python_version:
|
| 525 |
+
python_version = sys.version_info[:2]
|
| 526 |
+
platforms = list(platforms or platform_tags())
|
| 527 |
+
for version in _py_interpreter_range(python_version):
|
| 528 |
+
for platform_ in platforms:
|
| 529 |
+
yield Tag(version, "none", platform_)
|
| 530 |
+
if interpreter:
|
| 531 |
+
yield Tag(interpreter, "none", "any")
|
| 532 |
+
for version in _py_interpreter_range(python_version):
|
| 533 |
+
yield Tag(version, "none", "any")
|
| 534 |
+
|
| 535 |
+
|
| 536 |
+
def _mac_arch(arch: str, is_32bit: bool = _32_BIT_INTERPRETER) -> str:
|
| 537 |
+
if not is_32bit:
|
| 538 |
+
return arch
|
| 539 |
+
|
| 540 |
+
if arch.startswith("ppc"):
|
| 541 |
+
return "ppc"
|
| 542 |
+
|
| 543 |
+
return "i386"
|
| 544 |
+
|
| 545 |
+
|
| 546 |
+
def _mac_binary_formats(version: AppleVersion, cpu_arch: str) -> list[str]:
|
| 547 |
+
formats = [cpu_arch]
|
| 548 |
+
if cpu_arch == "x86_64":
|
| 549 |
+
if version < (10, 4):
|
| 550 |
+
return []
|
| 551 |
+
formats.extend(["intel", "fat64", "fat32"])
|
| 552 |
+
|
| 553 |
+
elif cpu_arch == "i386":
|
| 554 |
+
if version < (10, 4):
|
| 555 |
+
return []
|
| 556 |
+
formats.extend(["intel", "fat32", "fat"])
|
| 557 |
+
|
| 558 |
+
elif cpu_arch == "ppc64":
|
| 559 |
+
# TODO: Need to care about 32-bit PPC for ppc64 through 10.2?
|
| 560 |
+
if version > (10, 5) or version < (10, 4):
|
| 561 |
+
return []
|
| 562 |
+
formats.append("fat64")
|
| 563 |
+
|
| 564 |
+
elif cpu_arch == "ppc":
|
| 565 |
+
if version > (10, 6):
|
| 566 |
+
return []
|
| 567 |
+
formats.extend(["fat32", "fat"])
|
| 568 |
+
|
| 569 |
+
if cpu_arch in {"arm64", "x86_64"}:
|
| 570 |
+
formats.append("universal2")
|
| 571 |
+
|
| 572 |
+
if cpu_arch in {"x86_64", "i386", "ppc64", "ppc", "intel"}:
|
| 573 |
+
formats.append("universal")
|
| 574 |
+
|
| 575 |
+
return formats
|
| 576 |
+
|
| 577 |
+
|
| 578 |
+
def mac_platforms(
|
| 579 |
+
version: AppleVersion | None = None, arch: str | None = None
|
| 580 |
+
) -> Iterator[str]:
|
| 581 |
+
"""
|
| 582 |
+
Yields the :attr:`~Tag.platform` tags for macOS.
|
| 583 |
+
|
| 584 |
+
The `version` parameter is a two-item tuple specifying the macOS version to
|
| 585 |
+
generate platform tags for. The `arch` parameter is the CPU architecture to
|
| 586 |
+
generate platform tags for. Both parameters default to the appropriate value
|
| 587 |
+
for the current system.
|
| 588 |
+
|
| 589 |
+
:param tuple version: A two-item tuple representing the version of macOS.
|
| 590 |
+
Defaults to the current system's version.
|
| 591 |
+
:param str arch: The CPU architecture. Defaults to the architecture of the
|
| 592 |
+
current system, e.g. ``"x86_64"``.
|
| 593 |
+
|
| 594 |
+
.. note::
|
| 595 |
+
Equivalent support for the other major platforms is purposefully not
|
| 596 |
+
provided:
|
| 597 |
+
|
| 598 |
+
- On Windows, platform compatibility is statically specified
|
| 599 |
+
- On Linux, code must be run on the system itself to determine
|
| 600 |
+
compatibility
|
| 601 |
+
"""
|
| 602 |
+
version_str, _, cpu_arch = platform.mac_ver()
|
| 603 |
+
if version is None:
|
| 604 |
+
version = cast("AppleVersion", tuple(map(int, version_str.split(".")[:2])))
|
| 605 |
+
if version == (10, 16):
|
| 606 |
+
# When built against an older macOS SDK, Python will report macOS 10.16
|
| 607 |
+
# instead of the real version.
|
| 608 |
+
version_str = subprocess.run(
|
| 609 |
+
[
|
| 610 |
+
sys.executable,
|
| 611 |
+
"-sS",
|
| 612 |
+
"-c",
|
| 613 |
+
"import platform; print(platform.mac_ver()[0])",
|
| 614 |
+
],
|
| 615 |
+
check=True,
|
| 616 |
+
env={"SYSTEM_VERSION_COMPAT": "0"},
|
| 617 |
+
stdout=subprocess.PIPE,
|
| 618 |
+
text=True,
|
| 619 |
+
).stdout
|
| 620 |
+
version = cast("AppleVersion", tuple(map(int, version_str.split(".")[:2])))
|
| 621 |
+
|
| 622 |
+
if arch is None:
|
| 623 |
+
arch = _mac_arch(cpu_arch)
|
| 624 |
+
|
| 625 |
+
if (10, 0) <= version < (11, 0):
|
| 626 |
+
# Prior to Mac OS 11, each yearly release of Mac OS bumped the
|
| 627 |
+
# "minor" version number. The major version was always 10.
|
| 628 |
+
major_version = 10
|
| 629 |
+
for minor_version in range(version[1], -1, -1):
|
| 630 |
+
compat_version = major_version, minor_version
|
| 631 |
+
binary_formats = _mac_binary_formats(compat_version, arch)
|
| 632 |
+
for binary_format in binary_formats:
|
| 633 |
+
yield f"macosx_{major_version}_{minor_version}_{binary_format}"
|
| 634 |
+
|
| 635 |
+
if version >= (11, 0):
|
| 636 |
+
# Starting with Mac OS 11, each yearly release bumps the major version
|
| 637 |
+
# number. The minor versions are now the midyear updates.
|
| 638 |
+
minor_version = 0
|
| 639 |
+
for major_version in range(version[0], 10, -1):
|
| 640 |
+
compat_version = major_version, minor_version
|
| 641 |
+
binary_formats = _mac_binary_formats(compat_version, arch)
|
| 642 |
+
for binary_format in binary_formats:
|
| 643 |
+
yield f"macosx_{major_version}_{minor_version}_{binary_format}"
|
| 644 |
+
|
| 645 |
+
if version >= (11, 0):
|
| 646 |
+
# Mac OS 11 on x86_64 is compatible with binaries from previous releases.
|
| 647 |
+
# Arm64 support was introduced in 11.0, so no Arm binaries from previous
|
| 648 |
+
# releases exist.
|
| 649 |
+
#
|
| 650 |
+
# However, the "universal2" binary format can have a
|
| 651 |
+
# macOS version earlier than 11.0 when the x86_64 part of the binary supports
|
| 652 |
+
# that version of macOS.
|
| 653 |
+
major_version = 10
|
| 654 |
+
if arch == "x86_64":
|
| 655 |
+
for minor_version in range(16, 3, -1):
|
| 656 |
+
compat_version = major_version, minor_version
|
| 657 |
+
binary_formats = _mac_binary_formats(compat_version, arch)
|
| 658 |
+
for binary_format in binary_formats:
|
| 659 |
+
yield f"macosx_{major_version}_{minor_version}_{binary_format}"
|
| 660 |
+
else:
|
| 661 |
+
for minor_version in range(16, 3, -1):
|
| 662 |
+
compat_version = major_version, minor_version
|
| 663 |
+
binary_format = "universal2"
|
| 664 |
+
yield f"macosx_{major_version}_{minor_version}_{binary_format}"
|
| 665 |
+
|
| 666 |
+
|
| 667 |
+
def ios_platforms(
|
| 668 |
+
version: AppleVersion | None = None, multiarch: str | None = None
|
| 669 |
+
) -> Iterator[str]:
|
| 670 |
+
"""
|
| 671 |
+
|
| 672 |
+
Yields the :attr:`~Tag.platform` tags for iOS.
|
| 673 |
+
|
| 674 |
+
:param tuple version: A two-item tuple representing the version of iOS.
|
| 675 |
+
Defaults to the current system's version.
|
| 676 |
+
:param str multiarch: The CPU architecture+ABI to be used. This should be in
|
| 677 |
+
the format by ``sys.implementation._multiarch`` (e.g.,
|
| 678 |
+
``arm64_iphoneos`` or ``x86_64_iphonesimulator``).
|
| 679 |
+
Defaults to the current system's multiarch value.
|
| 680 |
+
|
| 681 |
+
.. note::
|
| 682 |
+
Behavior of this method is undefined if invoked on non-iOS platforms
|
| 683 |
+
without providing explicit version and multiarch arguments.
|
| 684 |
+
"""
|
| 685 |
+
if version is None:
|
| 686 |
+
# if iOS is the current platform, ios_ver *must* be defined. However,
|
| 687 |
+
# it won't exist for CPython versions before 3.13, which causes a mypy
|
| 688 |
+
# error.
|
| 689 |
+
_, release, _, _ = platform.ios_ver() # type: ignore[attr-defined, unused-ignore]
|
| 690 |
+
version = cast("AppleVersion", tuple(map(int, release.split(".")[:2])))
|
| 691 |
+
|
| 692 |
+
if multiarch is None:
|
| 693 |
+
multiarch = sys.implementation._multiarch
|
| 694 |
+
multiarch = multiarch.replace("-", "_")
|
| 695 |
+
|
| 696 |
+
ios_platform_template = "ios_{major}_{minor}_{multiarch}"
|
| 697 |
+
|
| 698 |
+
# Consider any iOS major.minor version from the version requested, down to
|
| 699 |
+
# 12.0. 12.0 is the first iOS version that is known to have enough features
|
| 700 |
+
# to support CPython. Consider every possible minor release up to X.9. There
|
| 701 |
+
# highest the minor has ever gone is 8 (14.8 and 15.8) but having some extra
|
| 702 |
+
# candidates that won't ever match doesn't really hurt, and it saves us from
|
| 703 |
+
# having to keep an explicit list of known iOS versions in the code. Return
|
| 704 |
+
# the results descending order of version number.
|
| 705 |
+
|
| 706 |
+
# If the requested major version is less than 12, there won't be any matches.
|
| 707 |
+
if version[0] < 12:
|
| 708 |
+
return
|
| 709 |
+
|
| 710 |
+
# Consider the actual X.Y version that was requested.
|
| 711 |
+
yield ios_platform_template.format(
|
| 712 |
+
major=version[0], minor=version[1], multiarch=multiarch
|
| 713 |
+
)
|
| 714 |
+
|
| 715 |
+
# Consider every minor version from X.0 to the minor version prior to the
|
| 716 |
+
# version requested by the platform.
|
| 717 |
+
for minor in range(version[1] - 1, -1, -1):
|
| 718 |
+
yield ios_platform_template.format(
|
| 719 |
+
major=version[0], minor=minor, multiarch=multiarch
|
| 720 |
+
)
|
| 721 |
+
|
| 722 |
+
for major in range(version[0] - 1, 11, -1):
|
| 723 |
+
for minor in range(9, -1, -1):
|
| 724 |
+
yield ios_platform_template.format(
|
| 725 |
+
major=major, minor=minor, multiarch=multiarch
|
| 726 |
+
)
|
| 727 |
+
|
| 728 |
+
|
| 729 |
+
def android_platforms(
|
| 730 |
+
api_level: int | None = None, abi: str | None = None
|
| 731 |
+
) -> Iterator[str]:
|
| 732 |
+
"""
|
| 733 |
+
Yields the :attr:`~Tag.platform` tags for Android. If this function is invoked on
|
| 734 |
+
non-Android platforms, the ``api_level`` and ``abi`` arguments are required.
|
| 735 |
+
|
| 736 |
+
:param int api_level: The maximum `API level
|
| 737 |
+
<https://developer.android.com/tools/releases/platforms>`__ to return. Defaults
|
| 738 |
+
to the current system's version, as returned by ``platform.android_ver``.
|
| 739 |
+
:param str abi: The `Android ABI <https://developer.android.com/ndk/guides/abis>`__,
|
| 740 |
+
e.g. ``arm64_v8a``. Defaults to the current system's ABI , as returned by
|
| 741 |
+
``sysconfig.get_platform``. Hyphens and periods will be replaced with
|
| 742 |
+
underscores.
|
| 743 |
+
"""
|
| 744 |
+
if platform.system() != "Android" and (api_level is None or abi is None):
|
| 745 |
+
raise TypeError(
|
| 746 |
+
"on non-Android platforms, the api_level and abi arguments are required"
|
| 747 |
+
)
|
| 748 |
+
|
| 749 |
+
if api_level is None:
|
| 750 |
+
# Python 3.13 was the first version to return platform.system() == "Android",
|
| 751 |
+
# and also the first version to define platform.android_ver().
|
| 752 |
+
api_level = platform.android_ver().api_level # type: ignore[attr-defined]
|
| 753 |
+
|
| 754 |
+
if abi is None:
|
| 755 |
+
abi = sysconfig.get_platform().split("-")[-1]
|
| 756 |
+
abi = _normalize_string(abi)
|
| 757 |
+
|
| 758 |
+
# 16 is the minimum API level known to have enough features to support CPython
|
| 759 |
+
# without major patching. Yield every API level from the maximum down to the
|
| 760 |
+
# minimum, inclusive.
|
| 761 |
+
min_api_level = 16
|
| 762 |
+
for ver in range(api_level, min_api_level - 1, -1):
|
| 763 |
+
yield f"android_{ver}_{abi}"
|
| 764 |
+
|
| 765 |
+
|
| 766 |
+
def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]:
|
| 767 |
+
linux = _normalize_string(sysconfig.get_platform())
|
| 768 |
+
if not linux.startswith("linux_"):
|
| 769 |
+
# we should never be here, just yield the sysconfig one and return
|
| 770 |
+
yield linux
|
| 771 |
+
return
|
| 772 |
+
if is_32bit:
|
| 773 |
+
if linux == "linux_x86_64":
|
| 774 |
+
linux = "linux_i686"
|
| 775 |
+
elif linux == "linux_aarch64":
|
| 776 |
+
linux = "linux_armv8l"
|
| 777 |
+
_, arch = linux.split("_", 1)
|
| 778 |
+
archs = {"armv8l": ["armv8l", "armv7l"]}.get(arch, [arch])
|
| 779 |
+
yield from _manylinux.platform_tags(archs)
|
| 780 |
+
yield from _musllinux.platform_tags(archs)
|
| 781 |
+
for arch in archs:
|
| 782 |
+
yield f"linux_{arch}"
|
| 783 |
+
|
| 784 |
+
|
| 785 |
+
def _emscripten_platforms() -> Iterator[str]:
|
| 786 |
+
pyemscripten_platform_version = sysconfig.get_config_var(
|
| 787 |
+
"PYEMSCRIPTEN_PLATFORM_VERSION"
|
| 788 |
+
)
|
| 789 |
+
if pyemscripten_platform_version:
|
| 790 |
+
yield f"pyemscripten_{pyemscripten_platform_version}_wasm32"
|
| 791 |
+
yield from _generic_platforms()
|
| 792 |
+
|
| 793 |
+
|
| 794 |
+
def _generic_platforms() -> Iterator[str]:
|
| 795 |
+
yield _normalize_string(sysconfig.get_platform())
|
| 796 |
+
|
| 797 |
+
|
| 798 |
+
def platform_tags() -> Iterator[str]:
|
| 799 |
+
"""
|
| 800 |
+
Yields the :attr:`~Tag.platform` tags for the running interpreter.
|
| 801 |
+
"""
|
| 802 |
+
if platform.system() == "Darwin":
|
| 803 |
+
return mac_platforms()
|
| 804 |
+
elif platform.system() == "iOS":
|
| 805 |
+
return ios_platforms()
|
| 806 |
+
elif platform.system() == "Android":
|
| 807 |
+
return android_platforms()
|
| 808 |
+
elif platform.system() == "Linux":
|
| 809 |
+
return _linux_platforms()
|
| 810 |
+
elif platform.system() == "Emscripten":
|
| 811 |
+
return _emscripten_platforms()
|
| 812 |
+
else:
|
| 813 |
+
return _generic_platforms()
|
| 814 |
+
|
| 815 |
+
|
| 816 |
+
def interpreter_name() -> str:
|
| 817 |
+
"""
|
| 818 |
+
Returns the name of the running interpreter.
|
| 819 |
+
|
| 820 |
+
Some implementations have a reserved, two-letter abbreviation which will
|
| 821 |
+
be returned when appropriate.
|
| 822 |
+
|
| 823 |
+
This typically acts as the prefix to the :attr:`~Tag.interpreter` tag.
|
| 824 |
+
"""
|
| 825 |
+
name = sys.implementation.name
|
| 826 |
+
return INTERPRETER_SHORT_NAMES.get(name) or name
|
| 827 |
+
|
| 828 |
+
|
| 829 |
+
def interpreter_version(*, warn: bool = False) -> str:
|
| 830 |
+
"""
|
| 831 |
+
Returns the running interpreter's version.
|
| 832 |
+
|
| 833 |
+
This typically acts as the suffix to the :attr:`~Tag.interpreter` tag.
|
| 834 |
+
|
| 835 |
+
:param bool warn: Whether warnings should be logged. Defaults to ``False``.
|
| 836 |
+
"""
|
| 837 |
+
version = _get_config_var("py_version_nodot", warn=warn)
|
| 838 |
+
return str(version) if version else _version_nodot(sys.version_info[:2])
|
| 839 |
+
|
| 840 |
+
|
| 841 |
+
def _version_nodot(version: PythonVersion) -> str:
|
| 842 |
+
return "".join(map(str, version))
|
| 843 |
+
|
| 844 |
+
|
| 845 |
+
def sys_tags(*, warn: bool = False) -> Iterator[Tag]:
|
| 846 |
+
"""
|
| 847 |
+
Yields the sequence of tag triples that the running interpreter supports.
|
| 848 |
+
|
| 849 |
+
The iterable is ordered so that the best-matching tag is first in the
|
| 850 |
+
sequence. The exact preferential order to tags is interpreter-specific, but
|
| 851 |
+
in general the tag importance is in the order of:
|
| 852 |
+
|
| 853 |
+
1. Interpreter
|
| 854 |
+
2. Platform
|
| 855 |
+
3. ABI
|
| 856 |
+
|
| 857 |
+
This order is due to the fact that an ABI is inherently tied to the
|
| 858 |
+
platform, but platform-specific code is not necessarily tied to the ABI. The
|
| 859 |
+
interpreter is the most important tag as it dictates basic support for any
|
| 860 |
+
wheel.
|
| 861 |
+
|
| 862 |
+
The function returns an iterable in order to allow for the possible
|
| 863 |
+
short-circuiting of tag generation if the entire sequence is not necessary
|
| 864 |
+
and tag calculation happens to be expensive.
|
| 865 |
+
|
| 866 |
+
:param bool warn: Whether warnings should be logged. Defaults to ``False``.
|
| 867 |
+
|
| 868 |
+
.. versionchanged:: 21.3
|
| 869 |
+
Added the `pp3-none-any` tag (:issue:`311`).
|
| 870 |
+
.. versionchanged:: 27.0
|
| 871 |
+
Added the `abi3t` tag (:issue:`1099`).
|
| 872 |
+
"""
|
| 873 |
+
|
| 874 |
+
interp_name = interpreter_name()
|
| 875 |
+
if interp_name == "cp":
|
| 876 |
+
yield from cpython_tags(warn=warn)
|
| 877 |
+
else:
|
| 878 |
+
yield from generic_tags()
|
| 879 |
+
|
| 880 |
+
if interp_name == "pp":
|
| 881 |
+
interp = "pp3"
|
| 882 |
+
elif interp_name == "cp":
|
| 883 |
+
interp = "cp" + interpreter_version(warn=warn)
|
| 884 |
+
else:
|
| 885 |
+
interp = None
|
| 886 |
+
yield from compatible_tags(interpreter=interp)
|
| 887 |
+
|
| 888 |
+
|
| 889 |
+
def create_compatible_tags_selector(
|
| 890 |
+
tags: Iterable[Tag],
|
| 891 |
+
) -> Callable[[Iterable[tuple[_T, AbstractSet[Tag]]]], Iterator[_T]]:
|
| 892 |
+
"""Create a callable to select things compatible with supported tags.
|
| 893 |
+
|
| 894 |
+
This function accepts an ordered sequence of tags, with the preferred
|
| 895 |
+
tags first.
|
| 896 |
+
|
| 897 |
+
The returned callable accepts an iterable of tuples (thing, set[Tag]),
|
| 898 |
+
and returns an iterator of things, with the things with the best
|
| 899 |
+
matching tags first.
|
| 900 |
+
|
| 901 |
+
Example to select compatible wheel filenames:
|
| 902 |
+
|
| 903 |
+
>>> from packaging import tags
|
| 904 |
+
>>> from packaging.utils import parse_wheel_filename
|
| 905 |
+
>>> selector = tags.create_compatible_tags_selector(tags.sys_tags())
|
| 906 |
+
>>> filenames = ["foo-1.0-py3-none-any.whl", "foo-1.0-py2-none-any.whl"]
|
| 907 |
+
>>> list(selector([
|
| 908 |
+
... (filename, parse_wheel_filename(filename)[-1]) for filename in filenames
|
| 909 |
+
... ]))
|
| 910 |
+
['foo-1.0-py3-none-any.whl']
|
| 911 |
+
|
| 912 |
+
.. versionadded:: 26.1
|
| 913 |
+
"""
|
| 914 |
+
tag_ranks: dict[Tag, int] = {}
|
| 915 |
+
for rank, tag in enumerate(tags):
|
| 916 |
+
tag_ranks.setdefault(tag, rank) # ignore duplicate tags, keep first
|
| 917 |
+
supported_tags = tag_ranks.keys()
|
| 918 |
+
|
| 919 |
+
def selector(
|
| 920 |
+
tagged_things: Iterable[tuple[_T, AbstractSet[Tag]]],
|
| 921 |
+
) -> Iterator[_T]:
|
| 922 |
+
ranked_things: list[tuple[_T, int]] = []
|
| 923 |
+
for thing, thing_tags in tagged_things:
|
| 924 |
+
supported_thing_tags = thing_tags & supported_tags
|
| 925 |
+
if supported_thing_tags:
|
| 926 |
+
thing_rank = min(tag_ranks[t] for t in supported_thing_tags)
|
| 927 |
+
ranked_things.append((thing, thing_rank))
|
| 928 |
+
return iter(
|
| 929 |
+
thing for thing, _ in sorted(ranked_things, key=operator.itemgetter(1))
|
| 930 |
+
)
|
| 931 |
+
|
| 932 |
+
return selector
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/utils.py
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
|
| 5 |
+
from __future__ import annotations
|
| 6 |
+
|
| 7 |
+
import re
|
| 8 |
+
from typing import NewType, Tuple, Union, cast
|
| 9 |
+
|
| 10 |
+
from .tags import Tag, UnsortedTagsError, parse_tag
|
| 11 |
+
from .version import InvalidVersion, Version, _TrimmedRelease
|
| 12 |
+
|
| 13 |
+
__all__ = [
|
| 14 |
+
"BuildTag",
|
| 15 |
+
"InvalidName",
|
| 16 |
+
"InvalidSdistFilename",
|
| 17 |
+
"InvalidWheelFilename",
|
| 18 |
+
"NormalizedName",
|
| 19 |
+
"canonicalize_name",
|
| 20 |
+
"canonicalize_version",
|
| 21 |
+
"is_normalized_name",
|
| 22 |
+
"parse_sdist_filename",
|
| 23 |
+
"parse_wheel_filename",
|
| 24 |
+
]
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def __dir__() -> list[str]:
|
| 28 |
+
return __all__
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
BuildTag = Union[Tuple[()], Tuple[int, str]]
|
| 32 |
+
|
| 33 |
+
NormalizedName = NewType("NormalizedName", str)
|
| 34 |
+
"""
|
| 35 |
+
A :class:`typing.NewType` of :class:`str`, representing a normalized name.
|
| 36 |
+
"""
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
class InvalidName(ValueError):
|
| 40 |
+
"""
|
| 41 |
+
An invalid distribution name; users should refer to the packaging user guide.
|
| 42 |
+
"""
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
class InvalidWheelFilename(ValueError):
|
| 46 |
+
"""
|
| 47 |
+
An invalid wheel filename was found, users should refer to PEP 427.
|
| 48 |
+
"""
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
class InvalidSdistFilename(ValueError):
|
| 52 |
+
"""
|
| 53 |
+
An invalid sdist filename was found, users should refer to the packaging user guide.
|
| 54 |
+
"""
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
# Core metadata spec for `Name`
|
| 58 |
+
_validate_regex = re.compile(
|
| 59 |
+
r"[a-z0-9]|[a-z0-9][a-z0-9._-]*[a-z0-9]", re.IGNORECASE | re.ASCII
|
| 60 |
+
)
|
| 61 |
+
_normalized_regex = re.compile(r"[a-z0-9]|[a-z0-9]([a-z0-9-](?!--))*[a-z0-9]", re.ASCII)
|
| 62 |
+
# PEP 427: The build number must start with a digit.
|
| 63 |
+
_build_tag_regex = re.compile(r"(\d+)(.*)", re.ASCII)
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def canonicalize_name(name: str, *, validate: bool = False) -> NormalizedName:
|
| 67 |
+
"""
|
| 68 |
+
This function takes a valid Python package or extra name, and returns the
|
| 69 |
+
normalized form of it.
|
| 70 |
+
|
| 71 |
+
The return type is typed as :class:`NormalizedName`. This allows type
|
| 72 |
+
checkers to help require that a string has passed through this function
|
| 73 |
+
before use.
|
| 74 |
+
|
| 75 |
+
If **validate** is true, then the function will check if **name** is a valid
|
| 76 |
+
distribution name before normalizing.
|
| 77 |
+
|
| 78 |
+
:param str name: The name to normalize.
|
| 79 |
+
:param bool validate: Check whether the name is a valid distribution name.
|
| 80 |
+
:raises InvalidName: If **validate** is true and the name is not an
|
| 81 |
+
acceptable distribution name.
|
| 82 |
+
|
| 83 |
+
>>> from packaging.utils import canonicalize_name
|
| 84 |
+
>>> canonicalize_name("Django")
|
| 85 |
+
'django'
|
| 86 |
+
>>> canonicalize_name("oslo.concurrency")
|
| 87 |
+
'oslo-concurrency'
|
| 88 |
+
>>> canonicalize_name("requests")
|
| 89 |
+
'requests'
|
| 90 |
+
"""
|
| 91 |
+
if validate and not _validate_regex.fullmatch(name):
|
| 92 |
+
raise InvalidName(f"name is invalid: {name!r}")
|
| 93 |
+
# Ensure all ``.`` and ``_`` are ``-``
|
| 94 |
+
# Emulates ``re.sub(r"[-_.]+", "-", name).lower()`` from PEP 503
|
| 95 |
+
# Much faster than re, and even faster than str.translate
|
| 96 |
+
value = name.lower().replace("_", "-").replace(".", "-")
|
| 97 |
+
# Condense repeats (faster than regex)
|
| 98 |
+
while "--" in value:
|
| 99 |
+
value = value.replace("--", "-")
|
| 100 |
+
return cast("NormalizedName", value)
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def is_normalized_name(name: str) -> bool:
|
| 104 |
+
"""
|
| 105 |
+
Check if a name is already normalized (i.e. :func:`canonicalize_name` would
|
| 106 |
+
roundtrip to the same value).
|
| 107 |
+
|
| 108 |
+
:param str name: The name to check.
|
| 109 |
+
|
| 110 |
+
>>> from packaging.utils import is_normalized_name
|
| 111 |
+
>>> is_normalized_name("requests")
|
| 112 |
+
True
|
| 113 |
+
>>> is_normalized_name("Django")
|
| 114 |
+
False
|
| 115 |
+
"""
|
| 116 |
+
return _normalized_regex.fullmatch(name) is not None
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
def canonicalize_version(
|
| 120 |
+
version: Version | str, *, strip_trailing_zero: bool = True
|
| 121 |
+
) -> str:
|
| 122 |
+
"""Return a canonical form of a version as a string.
|
| 123 |
+
|
| 124 |
+
This function takes a string representing a package version (or a
|
| 125 |
+
:class:`~packaging.version.Version` instance), and returns the
|
| 126 |
+
normalized form of it. By default, it strips trailing zeros from
|
| 127 |
+
the release segment.
|
| 128 |
+
|
| 129 |
+
>>> from packaging.utils import canonicalize_version
|
| 130 |
+
>>> canonicalize_version('1.0.1')
|
| 131 |
+
'1.0.1'
|
| 132 |
+
|
| 133 |
+
Per PEP 625, versions may have multiple canonical forms, differing
|
| 134 |
+
only by trailing zeros.
|
| 135 |
+
|
| 136 |
+
>>> canonicalize_version('1.0.0')
|
| 137 |
+
'1'
|
| 138 |
+
>>> canonicalize_version('1.0.0', strip_trailing_zero=False)
|
| 139 |
+
'1.0.0'
|
| 140 |
+
|
| 141 |
+
Invalid versions are returned unaltered.
|
| 142 |
+
|
| 143 |
+
>>> canonicalize_version('foo bar baz')
|
| 144 |
+
'foo bar baz'
|
| 145 |
+
|
| 146 |
+
>>> canonicalize_version('1.4.0.0.0')
|
| 147 |
+
'1.4'
|
| 148 |
+
"""
|
| 149 |
+
if isinstance(version, str):
|
| 150 |
+
try:
|
| 151 |
+
version = Version(version)
|
| 152 |
+
except InvalidVersion:
|
| 153 |
+
return str(version)
|
| 154 |
+
return str(_TrimmedRelease(version) if strip_trailing_zero else version)
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
def parse_wheel_filename(
|
| 158 |
+
filename: str,
|
| 159 |
+
*,
|
| 160 |
+
validate_order: bool = False,
|
| 161 |
+
) -> tuple[NormalizedName, Version, BuildTag, frozenset[Tag]]:
|
| 162 |
+
"""
|
| 163 |
+
This function takes the filename of a wheel file, and parses it,
|
| 164 |
+
returning a tuple of name, version, build number, and tags.
|
| 165 |
+
|
| 166 |
+
The name part of the tuple is normalized and typed as
|
| 167 |
+
:class:`NormalizedName`. The version portion is an instance of
|
| 168 |
+
:class:`~packaging.version.Version`. The build number is ``()`` if
|
| 169 |
+
there is no build number in the wheel filename, otherwise a
|
| 170 |
+
two-item tuple of an integer for the leading digits and
|
| 171 |
+
a string for the rest of the build number. The tags portion is a
|
| 172 |
+
frozen set of :class:`~packaging.tags.Tag` instances (as the tag
|
| 173 |
+
string format allows multiple tags to be combined into a single
|
| 174 |
+
string).
|
| 175 |
+
|
| 176 |
+
If **validate_order** is true, compressed tag set components are
|
| 177 |
+
checked to be in sorted order as required by PEP 425.
|
| 178 |
+
|
| 179 |
+
:param str filename: The name of the wheel file.
|
| 180 |
+
:param bool validate_order: Check whether compressed tag set components
|
| 181 |
+
are in sorted order.
|
| 182 |
+
:raises InvalidWheelFilename: If the filename in question
|
| 183 |
+
does not follow the :ref:`wheel specification
|
| 184 |
+
<pypug:binary-distribution-format>`.
|
| 185 |
+
|
| 186 |
+
>>> from packaging.utils import parse_wheel_filename
|
| 187 |
+
>>> from packaging.tags import Tag
|
| 188 |
+
>>> from packaging.version import Version
|
| 189 |
+
>>> name, ver, build, tags = parse_wheel_filename("foo-1.0-py3-none-any.whl")
|
| 190 |
+
>>> name
|
| 191 |
+
'foo'
|
| 192 |
+
>>> ver == Version('1.0')
|
| 193 |
+
True
|
| 194 |
+
>>> tags == {Tag("py3", "none", "any")}
|
| 195 |
+
True
|
| 196 |
+
>>> not build
|
| 197 |
+
True
|
| 198 |
+
|
| 199 |
+
.. versionadded:: 26.1
|
| 200 |
+
The *validate_order* parameter.
|
| 201 |
+
"""
|
| 202 |
+
if not filename.endswith(".whl"):
|
| 203 |
+
raise InvalidWheelFilename(
|
| 204 |
+
f"Invalid wheel filename (extension must be '.whl'): {filename!r}"
|
| 205 |
+
)
|
| 206 |
+
|
| 207 |
+
filename = filename[:-4]
|
| 208 |
+
dashes = filename.count("-")
|
| 209 |
+
if dashes not in (4, 5):
|
| 210 |
+
raise InvalidWheelFilename(
|
| 211 |
+
f"Invalid wheel filename (wrong number of parts): {filename!r}"
|
| 212 |
+
)
|
| 213 |
+
|
| 214 |
+
parts = filename.split("-", dashes - 2)
|
| 215 |
+
name_part = parts[0]
|
| 216 |
+
# See PEP 427 for the rules on escaping the project name.
|
| 217 |
+
if "__" in name_part or re.match(r"^[\w\d._]*$", name_part, re.UNICODE) is None:
|
| 218 |
+
raise InvalidWheelFilename(f"Invalid project name: {filename!r}")
|
| 219 |
+
name = canonicalize_name(name_part)
|
| 220 |
+
|
| 221 |
+
try:
|
| 222 |
+
version = Version(parts[1])
|
| 223 |
+
except InvalidVersion as e:
|
| 224 |
+
raise InvalidWheelFilename(
|
| 225 |
+
f"Invalid wheel filename (invalid version): {filename!r}"
|
| 226 |
+
) from e
|
| 227 |
+
|
| 228 |
+
if dashes == 5:
|
| 229 |
+
build_part = parts[2]
|
| 230 |
+
build_match = _build_tag_regex.match(build_part)
|
| 231 |
+
if build_match is None:
|
| 232 |
+
raise InvalidWheelFilename(
|
| 233 |
+
f"Invalid build number: {build_part} in {filename!r}"
|
| 234 |
+
)
|
| 235 |
+
build = cast("BuildTag", (int(build_match.group(1)), build_match.group(2)))
|
| 236 |
+
else:
|
| 237 |
+
build = ()
|
| 238 |
+
tag_str = parts[-1]
|
| 239 |
+
try:
|
| 240 |
+
tags = parse_tag(tag_str, validate_order=validate_order)
|
| 241 |
+
except UnsortedTagsError:
|
| 242 |
+
raise InvalidWheelFilename(
|
| 243 |
+
f"Invalid wheel filename (compressed tag set components must be in "
|
| 244 |
+
f"sorted order per PEP 425): {filename!r}"
|
| 245 |
+
) from None
|
| 246 |
+
return (name, version, build, tags)
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
def parse_sdist_filename(filename: str) -> tuple[NormalizedName, Version]:
|
| 250 |
+
"""
|
| 251 |
+
This function takes the filename of a sdist file (as specified
|
| 252 |
+
in the `Source distribution format`_ documentation), and parses
|
| 253 |
+
it, returning a tuple of the normalized name and version as
|
| 254 |
+
represented by an instance of :class:`~packaging.version.Version`.
|
| 255 |
+
|
| 256 |
+
:param str filename: The name of the sdist file.
|
| 257 |
+
:raises InvalidSdistFilename: If the filename does not end
|
| 258 |
+
with an sdist extension (``.zip`` or ``.tar.gz``), or if it does not
|
| 259 |
+
contain a dash separating the name and the version of the distribution.
|
| 260 |
+
|
| 261 |
+
>>> from packaging.utils import parse_sdist_filename
|
| 262 |
+
>>> from packaging.version import Version
|
| 263 |
+
>>> name, ver = parse_sdist_filename("foo-1.0.tar.gz")
|
| 264 |
+
>>> name
|
| 265 |
+
'foo'
|
| 266 |
+
>>> ver == Version('1.0')
|
| 267 |
+
True
|
| 268 |
+
|
| 269 |
+
.. _Source distribution format: https://packaging.python.org/specifications/source-distribution-format/#source-distribution-file-name
|
| 270 |
+
"""
|
| 271 |
+
if filename.endswith(".tar.gz"):
|
| 272 |
+
file_stem = filename[: -len(".tar.gz")]
|
| 273 |
+
elif filename.endswith(".zip"):
|
| 274 |
+
file_stem = filename[: -len(".zip")]
|
| 275 |
+
else:
|
| 276 |
+
raise InvalidSdistFilename(
|
| 277 |
+
f"Invalid sdist filename (extension must be '.tar.gz' or '.zip'):"
|
| 278 |
+
f" {filename!r}"
|
| 279 |
+
)
|
| 280 |
+
|
| 281 |
+
# We are requiring a PEP 440 version, which cannot contain dashes,
|
| 282 |
+
# so we split on the last dash.
|
| 283 |
+
name_part, sep, version_part = file_stem.rpartition("-")
|
| 284 |
+
if not sep:
|
| 285 |
+
raise InvalidSdistFilename(f"Invalid sdist filename: {filename!r}")
|
| 286 |
+
|
| 287 |
+
name = canonicalize_name(name_part)
|
| 288 |
+
|
| 289 |
+
try:
|
| 290 |
+
version = Version(version_part)
|
| 291 |
+
except InvalidVersion as e:
|
| 292 |
+
raise InvalidSdistFilename(
|
| 293 |
+
f"Invalid sdist filename (invalid version): {filename!r}"
|
| 294 |
+
) from e
|
| 295 |
+
|
| 296 |
+
return (name, version)
|
.venv/lib/python3.14/site-packages/pip/_vendor/packaging/version.py
ADDED
|
@@ -0,0 +1,1231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
"""
|
| 5 |
+
.. testsetup::
|
| 6 |
+
|
| 7 |
+
from pip._vendor.packaging.version import parse, normalize_pre, Version, _cmpkey
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
from __future__ import annotations
|
| 11 |
+
|
| 12 |
+
import re
|
| 13 |
+
import sys
|
| 14 |
+
import typing
|
| 15 |
+
from typing import (
|
| 16 |
+
Any,
|
| 17 |
+
Callable,
|
| 18 |
+
Literal,
|
| 19 |
+
NamedTuple,
|
| 20 |
+
SupportsInt,
|
| 21 |
+
Tuple,
|
| 22 |
+
TypedDict,
|
| 23 |
+
Union,
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
if typing.TYPE_CHECKING:
|
| 27 |
+
from typing_extensions import Self, Unpack
|
| 28 |
+
|
| 29 |
+
if sys.version_info >= (3, 13): # pragma: no cover
|
| 30 |
+
from warnings import deprecated as _deprecated
|
| 31 |
+
elif typing.TYPE_CHECKING:
|
| 32 |
+
from typing_extensions import deprecated as _deprecated
|
| 33 |
+
else: # pragma: no cover
|
| 34 |
+
import functools
|
| 35 |
+
import warnings
|
| 36 |
+
|
| 37 |
+
def _deprecated(message: str) -> object:
|
| 38 |
+
def decorator(func: Callable[[...], object]) -> object:
|
| 39 |
+
@functools.wraps(func)
|
| 40 |
+
def wrapper(*args: object, **kwargs: object) -> object:
|
| 41 |
+
warnings.warn(
|
| 42 |
+
message,
|
| 43 |
+
category=DeprecationWarning,
|
| 44 |
+
stacklevel=2,
|
| 45 |
+
)
|
| 46 |
+
return func(*args, **kwargs)
|
| 47 |
+
|
| 48 |
+
return wrapper
|
| 49 |
+
|
| 50 |
+
return decorator
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
_LETTER_NORMALIZATION = {
|
| 54 |
+
"alpha": "a",
|
| 55 |
+
"beta": "b",
|
| 56 |
+
"c": "rc",
|
| 57 |
+
"pre": "rc",
|
| 58 |
+
"preview": "rc",
|
| 59 |
+
"rev": "post",
|
| 60 |
+
"r": "post",
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
__all__ = ["VERSION_PATTERN", "InvalidVersion", "Version", "normalize_pre", "parse"]
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def __dir__() -> list[str]:
|
| 67 |
+
return __all__
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
LocalType = Tuple[Union[int, str], ...]
|
| 71 |
+
|
| 72 |
+
CmpLocalType = Tuple[Tuple[int, str], ...]
|
| 73 |
+
CmpSuffix = Tuple[int, int, int, int, int, int]
|
| 74 |
+
CmpKey = Union[
|
| 75 |
+
Tuple[int, Tuple[int, ...], CmpSuffix],
|
| 76 |
+
Tuple[int, Tuple[int, ...], CmpSuffix, CmpLocalType],
|
| 77 |
+
]
|
| 78 |
+
VersionComparisonMethod = Callable[[CmpKey, CmpKey], bool]
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
class _VersionReplace(TypedDict, total=False):
|
| 82 |
+
epoch: int | None
|
| 83 |
+
release: tuple[int, ...] | None
|
| 84 |
+
pre: tuple[str, int] | None
|
| 85 |
+
post: int | None
|
| 86 |
+
dev: int | None
|
| 87 |
+
local: str | None
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def normalize_pre(letter: str, /) -> str:
|
| 91 |
+
"""Normalize the pre-release segment of a version string.
|
| 92 |
+
|
| 93 |
+
Returns a lowercase version of the string if not a known pre-release
|
| 94 |
+
identifier.
|
| 95 |
+
|
| 96 |
+
>>> normalize_pre('alpha')
|
| 97 |
+
'a'
|
| 98 |
+
>>> normalize_pre('BETA')
|
| 99 |
+
'b'
|
| 100 |
+
>>> normalize_pre('rc')
|
| 101 |
+
'rc'
|
| 102 |
+
|
| 103 |
+
:param letter:
|
| 104 |
+
|
| 105 |
+
.. versionadded:: 26.1
|
| 106 |
+
"""
|
| 107 |
+
letter = letter.lower()
|
| 108 |
+
return _LETTER_NORMALIZATION.get(letter, letter)
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def parse(version: str) -> Version:
|
| 112 |
+
"""Parse the given version string.
|
| 113 |
+
|
| 114 |
+
This is identical to the :class:`Version` constructor.
|
| 115 |
+
|
| 116 |
+
>>> parse('1.0.dev1')
|
| 117 |
+
<Version('1.0.dev1')>
|
| 118 |
+
|
| 119 |
+
:param version: The version string to parse.
|
| 120 |
+
:raises InvalidVersion: When the version string is not a valid version.
|
| 121 |
+
"""
|
| 122 |
+
return Version(version)
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
class InvalidVersion(ValueError):
|
| 126 |
+
"""Raised when a version string is not a valid version.
|
| 127 |
+
|
| 128 |
+
>>> Version("invalid")
|
| 129 |
+
Traceback (most recent call last):
|
| 130 |
+
...
|
| 131 |
+
packaging.version.InvalidVersion: Invalid version: 'invalid'
|
| 132 |
+
"""
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
class _BaseVersion:
|
| 136 |
+
__slots__ = ()
|
| 137 |
+
|
| 138 |
+
# This can also be a normal member (see the packaging_legacy package);
|
| 139 |
+
# we are just requiring it to be readable. Actually defining a property
|
| 140 |
+
# has runtime effect on subclasses, so it's typing only.
|
| 141 |
+
if typing.TYPE_CHECKING:
|
| 142 |
+
|
| 143 |
+
@property
|
| 144 |
+
def _key(self) -> tuple[Any, ...]: ...
|
| 145 |
+
|
| 146 |
+
def __hash__(self) -> int:
|
| 147 |
+
return hash(self._key)
|
| 148 |
+
|
| 149 |
+
# Please keep the duplicated `isinstance` check
|
| 150 |
+
# in the six comparisons hereunder
|
| 151 |
+
# unless you find a way to avoid adding overhead function calls.
|
| 152 |
+
def __lt__(self, other: _BaseVersion) -> bool:
|
| 153 |
+
if not isinstance(other, _BaseVersion):
|
| 154 |
+
return NotImplemented
|
| 155 |
+
|
| 156 |
+
return self._key < other._key
|
| 157 |
+
|
| 158 |
+
def __le__(self, other: _BaseVersion) -> bool:
|
| 159 |
+
if not isinstance(other, _BaseVersion):
|
| 160 |
+
return NotImplemented
|
| 161 |
+
|
| 162 |
+
return self._key <= other._key
|
| 163 |
+
|
| 164 |
+
def __eq__(self, other: object) -> bool:
|
| 165 |
+
if not isinstance(other, _BaseVersion):
|
| 166 |
+
return NotImplemented
|
| 167 |
+
|
| 168 |
+
return self._key == other._key
|
| 169 |
+
|
| 170 |
+
def __ge__(self, other: _BaseVersion) -> bool:
|
| 171 |
+
if not isinstance(other, _BaseVersion):
|
| 172 |
+
return NotImplemented
|
| 173 |
+
|
| 174 |
+
return self._key >= other._key
|
| 175 |
+
|
| 176 |
+
def __gt__(self, other: _BaseVersion) -> bool:
|
| 177 |
+
if not isinstance(other, _BaseVersion):
|
| 178 |
+
return NotImplemented
|
| 179 |
+
|
| 180 |
+
return self._key > other._key
|
| 181 |
+
|
| 182 |
+
def __ne__(self, other: object) -> bool:
|
| 183 |
+
if not isinstance(other, _BaseVersion):
|
| 184 |
+
return NotImplemented
|
| 185 |
+
|
| 186 |
+
return self._key != other._key
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
# Deliberately not anchored to the start and end of the string, to make it
|
| 190 |
+
# easier for 3rd party code to reuse
|
| 191 |
+
|
| 192 |
+
# Note that ++ doesn't behave identically on CPython and PyPy, so not using it here
|
| 193 |
+
_VERSION_PATTERN = r"""
|
| 194 |
+
v?+ # optional leading v
|
| 195 |
+
(?a:
|
| 196 |
+
(?:(?P<epoch>[0-9]+)!)?+ # epoch
|
| 197 |
+
(?P<release>[0-9]+(?:\.[0-9]+)*+) # release segment
|
| 198 |
+
(?P<pre> # pre-release
|
| 199 |
+
[._-]?+
|
| 200 |
+
(?P<pre_l>alpha|a|beta|b|preview|pre|c|rc)
|
| 201 |
+
[._-]?+
|
| 202 |
+
(?P<pre_n>[0-9]+)?
|
| 203 |
+
)?+
|
| 204 |
+
(?P<post> # post release
|
| 205 |
+
(?:-(?P<post_n1>[0-9]+))
|
| 206 |
+
|
|
| 207 |
+
(?:
|
| 208 |
+
[._-]?
|
| 209 |
+
(?P<post_l>post|rev|r)
|
| 210 |
+
[._-]?
|
| 211 |
+
(?P<post_n2>[0-9]+)?
|
| 212 |
+
)
|
| 213 |
+
)?+
|
| 214 |
+
(?P<dev> # dev release
|
| 215 |
+
[._-]?+
|
| 216 |
+
(?P<dev_l>dev)
|
| 217 |
+
[._-]?+
|
| 218 |
+
(?P<dev_n>[0-9]+)?
|
| 219 |
+
)?+
|
| 220 |
+
)
|
| 221 |
+
(?a:\+
|
| 222 |
+
(?P<local> # local version
|
| 223 |
+
[a-z0-9]+
|
| 224 |
+
(?:[._-][a-z0-9]+)*+
|
| 225 |
+
)
|
| 226 |
+
)?+
|
| 227 |
+
"""
|
| 228 |
+
|
| 229 |
+
_VERSION_PATTERN_OLD = _VERSION_PATTERN.replace("*+", "*").replace("?+", "?")
|
| 230 |
+
|
| 231 |
+
# Possessive qualifiers were added in Python 3.11.
|
| 232 |
+
# CPython 3.11.0-3.11.4 had a bug: https://github.com/python/cpython/pull/107795
|
| 233 |
+
# Older PyPy also had a bug.
|
| 234 |
+
VERSION_PATTERN = (
|
| 235 |
+
_VERSION_PATTERN_OLD
|
| 236 |
+
if (sys.implementation.name == "cpython" and sys.version_info < (3, 11, 5))
|
| 237 |
+
or (sys.implementation.name == "pypy" and sys.version_info < (3, 11, 13))
|
| 238 |
+
or sys.version_info < (3, 11)
|
| 239 |
+
else _VERSION_PATTERN
|
| 240 |
+
)
|
| 241 |
+
"""
|
| 242 |
+
A string containing the regular expression used to match a valid version.
|
| 243 |
+
|
| 244 |
+
The pattern is not anchored at either end, and is intended for embedding in larger
|
| 245 |
+
expressions (for example, matching a version number as part of a file name). The
|
| 246 |
+
regular expression should be compiled with the ``re.VERBOSE`` and ``re.IGNORECASE``
|
| 247 |
+
flags set.
|
| 248 |
+
|
| 249 |
+
.. versionchanged:: 26.0
|
| 250 |
+
|
| 251 |
+
The regex now uses possessive qualifiers on Python 3.11 if they are
|
| 252 |
+
supported (CPython 3.11.5+, PyPy 3.11.13+).
|
| 253 |
+
|
| 254 |
+
:meta hide-value:
|
| 255 |
+
"""
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
# Validation pattern for local version in replace()
|
| 259 |
+
_LOCAL_PATTERN = re.compile(r"[a-z0-9]+(?:[._-][a-z0-9]+)*", re.IGNORECASE | re.ASCII)
|
| 260 |
+
|
| 261 |
+
# Fast path: If a version has only digits and dots then we
|
| 262 |
+
# can skip the regex and parse it as a release segment
|
| 263 |
+
_SIMPLE_VERSION_INDICATORS = frozenset(".0123456789")
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
def _validate_epoch(value: object, /) -> int:
|
| 267 |
+
epoch = value or 0
|
| 268 |
+
if isinstance(epoch, int) and epoch >= 0:
|
| 269 |
+
return epoch
|
| 270 |
+
msg = f"epoch must be non-negative integer, got {epoch}"
|
| 271 |
+
raise InvalidVersion(msg)
|
| 272 |
+
|
| 273 |
+
|
| 274 |
+
def _validate_release(value: object, /) -> tuple[int, ...]:
|
| 275 |
+
release = (0,) if value is None else value
|
| 276 |
+
if (
|
| 277 |
+
isinstance(release, tuple)
|
| 278 |
+
and len(release) > 0
|
| 279 |
+
and all(isinstance(i, int) and i >= 0 for i in release)
|
| 280 |
+
):
|
| 281 |
+
return release
|
| 282 |
+
msg = f"release must be a non-empty tuple of non-negative integers, got {release}"
|
| 283 |
+
raise InvalidVersion(msg)
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
def _validate_pre(value: object, /) -> tuple[Literal["a", "b", "rc"], int] | None:
|
| 287 |
+
if value is None:
|
| 288 |
+
return value
|
| 289 |
+
if isinstance(value, tuple) and len(value) == 2:
|
| 290 |
+
letter, number = value
|
| 291 |
+
letter = normalize_pre(letter)
|
| 292 |
+
if letter in {"a", "b", "rc"} and isinstance(number, int) and number >= 0:
|
| 293 |
+
# type checkers can't infer the Literal type here on letter
|
| 294 |
+
return (letter, number) # type: ignore[return-value]
|
| 295 |
+
msg = f"pre must be a tuple of ('a'|'b'|'rc', non-negative int), got {value}"
|
| 296 |
+
raise InvalidVersion(msg)
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
def _validate_post(value: object, /) -> tuple[Literal["post"], int] | None:
|
| 300 |
+
if value is None:
|
| 301 |
+
return value
|
| 302 |
+
if isinstance(value, int) and value >= 0:
|
| 303 |
+
return ("post", value)
|
| 304 |
+
msg = f"post must be non-negative integer, got {value}"
|
| 305 |
+
raise InvalidVersion(msg)
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
def _validate_dev(value: object, /) -> tuple[Literal["dev"], int] | None:
|
| 309 |
+
if value is None:
|
| 310 |
+
return value
|
| 311 |
+
if isinstance(value, int) and value >= 0:
|
| 312 |
+
return ("dev", value)
|
| 313 |
+
msg = f"dev must be non-negative integer, got {value}"
|
| 314 |
+
raise InvalidVersion(msg)
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
def _validate_local(value: object, /) -> LocalType | None:
|
| 318 |
+
if value is None:
|
| 319 |
+
return value
|
| 320 |
+
if isinstance(value, str) and _LOCAL_PATTERN.fullmatch(value):
|
| 321 |
+
return _parse_local_version(value)
|
| 322 |
+
msg = f"local must be a valid version string, got {value!r}"
|
| 323 |
+
raise InvalidVersion(msg)
|
| 324 |
+
|
| 325 |
+
|
| 326 |
+
# Backward compatibility for internals before 26.0. Do not use.
|
| 327 |
+
class _Version(NamedTuple):
|
| 328 |
+
epoch: int
|
| 329 |
+
release: tuple[int, ...]
|
| 330 |
+
dev: tuple[Literal["dev"], int] | None
|
| 331 |
+
pre: tuple[Literal["a", "b", "rc"], int] | None
|
| 332 |
+
post: tuple[Literal["post"], int] | None
|
| 333 |
+
local: LocalType | None
|
| 334 |
+
|
| 335 |
+
|
| 336 |
+
class Version(_BaseVersion):
|
| 337 |
+
"""This class abstracts handling of a project's versions.
|
| 338 |
+
|
| 339 |
+
A :class:`Version` instance is comparison aware and can be compared and
|
| 340 |
+
sorted using the standard Python interfaces.
|
| 341 |
+
|
| 342 |
+
>>> v1 = Version("1.0a5")
|
| 343 |
+
>>> v2 = Version("1.0")
|
| 344 |
+
>>> v1
|
| 345 |
+
<Version('1.0a5')>
|
| 346 |
+
>>> v2
|
| 347 |
+
<Version('1.0')>
|
| 348 |
+
>>> v1 < v2
|
| 349 |
+
True
|
| 350 |
+
>>> v1 == v2
|
| 351 |
+
False
|
| 352 |
+
>>> v1 > v2
|
| 353 |
+
False
|
| 354 |
+
>>> v1 >= v2
|
| 355 |
+
False
|
| 356 |
+
>>> v1 <= v2
|
| 357 |
+
True
|
| 358 |
+
|
| 359 |
+
:class:`Version` is immutable; use :meth:`__replace__` to change
|
| 360 |
+
part of a version.
|
| 361 |
+
|
| 362 |
+
Instances are safe to serialize with :mod:`pickle`. They use a stable
|
| 363 |
+
format so the same pickle can be loaded in future packaging releases.
|
| 364 |
+
|
| 365 |
+
.. versionchanged:: 26.2
|
| 366 |
+
|
| 367 |
+
Added a stable pickle format. Pickles created with packaging 26.2+ can
|
| 368 |
+
be unpickled with future releases. Backward compatibility with pickles
|
| 369 |
+
from pip._vendor.packaging < 26.2 is supported but may be removed in a future
|
| 370 |
+
release.
|
| 371 |
+
"""
|
| 372 |
+
|
| 373 |
+
__slots__ = (
|
| 374 |
+
"_dev",
|
| 375 |
+
"_epoch",
|
| 376 |
+
"_hash_cache",
|
| 377 |
+
"_key_cache",
|
| 378 |
+
"_local",
|
| 379 |
+
"_post",
|
| 380 |
+
"_pre",
|
| 381 |
+
"_release",
|
| 382 |
+
)
|
| 383 |
+
__match_args__ = ("_str",)
|
| 384 |
+
"""
|
| 385 |
+
Pattern matching is supported on Python 3.10+.
|
| 386 |
+
|
| 387 |
+
.. versionadded:: 26.0
|
| 388 |
+
|
| 389 |
+
:meta hide-value:
|
| 390 |
+
"""
|
| 391 |
+
|
| 392 |
+
_regex = re.compile(r"\s*" + VERSION_PATTERN + r"\s*", re.VERBOSE | re.IGNORECASE)
|
| 393 |
+
|
| 394 |
+
_epoch: int
|
| 395 |
+
_release: tuple[int, ...]
|
| 396 |
+
_dev: tuple[Literal["dev"], int] | None
|
| 397 |
+
_pre: tuple[Literal["a", "b", "rc"], int] | None
|
| 398 |
+
_post: tuple[Literal["post"], int] | None
|
| 399 |
+
_local: LocalType | None
|
| 400 |
+
|
| 401 |
+
_hash_cache: int | None
|
| 402 |
+
_key_cache: CmpKey | None
|
| 403 |
+
|
| 404 |
+
def __init__(self, version: str) -> None:
|
| 405 |
+
"""Initialize a Version object.
|
| 406 |
+
|
| 407 |
+
:param version:
|
| 408 |
+
The string representation of a version which will be parsed and normalized
|
| 409 |
+
before use.
|
| 410 |
+
:raises InvalidVersion:
|
| 411 |
+
If the ``version`` does not conform to PEP 440 in any way then this
|
| 412 |
+
exception will be raised.
|
| 413 |
+
"""
|
| 414 |
+
if _SIMPLE_VERSION_INDICATORS.issuperset(version):
|
| 415 |
+
try:
|
| 416 |
+
self._release = tuple(map(int, version.split(".")))
|
| 417 |
+
except ValueError:
|
| 418 |
+
# Empty parts (from "1..2", ".1", etc.) are invalid versions.
|
| 419 |
+
# Any other ValueError (e.g. int str-digits limit) should
|
| 420 |
+
# propagate to the caller.
|
| 421 |
+
if "" in version.split("."):
|
| 422 |
+
raise InvalidVersion(f"Invalid version: {version!r}") from None
|
| 423 |
+
# TODO: remove "no cover" when Python 3.9 is dropped.
|
| 424 |
+
raise # pragma: no cover
|
| 425 |
+
|
| 426 |
+
self._epoch = 0
|
| 427 |
+
self._pre = None
|
| 428 |
+
self._post = None
|
| 429 |
+
self._dev = None
|
| 430 |
+
self._local = None
|
| 431 |
+
self._key_cache = None
|
| 432 |
+
self._hash_cache = None
|
| 433 |
+
return
|
| 434 |
+
|
| 435 |
+
# Validate the version and parse it into pieces
|
| 436 |
+
match = self._regex.fullmatch(version)
|
| 437 |
+
if not match:
|
| 438 |
+
raise InvalidVersion(f"Invalid version: {version!r}")
|
| 439 |
+
self._epoch = int(match.group("epoch")) if match.group("epoch") else 0
|
| 440 |
+
self._release = tuple(map(int, match.group("release").split(".")))
|
| 441 |
+
# We can type ignore the assignments below because the regex guarantees
|
| 442 |
+
# the correct strings
|
| 443 |
+
self._pre = _parse_letter_version(match.group("pre_l"), match.group("pre_n")) # type: ignore[assignment]
|
| 444 |
+
self._post = _parse_letter_version( # type: ignore[assignment]
|
| 445 |
+
match.group("post_l"), match.group("post_n1") or match.group("post_n2")
|
| 446 |
+
)
|
| 447 |
+
self._dev = _parse_letter_version(match.group("dev_l"), match.group("dev_n")) # type: ignore[assignment]
|
| 448 |
+
self._local = _parse_local_version(match.group("local"))
|
| 449 |
+
|
| 450 |
+
# Key which will be used for sorting
|
| 451 |
+
self._key_cache = None
|
| 452 |
+
self._hash_cache = None
|
| 453 |
+
|
| 454 |
+
@classmethod
|
| 455 |
+
def from_parts(
|
| 456 |
+
cls,
|
| 457 |
+
*,
|
| 458 |
+
epoch: int = 0,
|
| 459 |
+
release: tuple[int, ...],
|
| 460 |
+
pre: tuple[str, int] | None = None,
|
| 461 |
+
post: int | None = None,
|
| 462 |
+
dev: int | None = None,
|
| 463 |
+
local: str | None = None,
|
| 464 |
+
) -> Self:
|
| 465 |
+
"""
|
| 466 |
+
Return a new version composed of the various parts.
|
| 467 |
+
|
| 468 |
+
This allows you to build a version without going though a string and
|
| 469 |
+
running a regular expression. It normalizes pre-release strings. The
|
| 470 |
+
``release=`` keyword argument is required.
|
| 471 |
+
|
| 472 |
+
>>> Version.from_parts(release=(1,2,3))
|
| 473 |
+
<Version('1.2.3')>
|
| 474 |
+
>>> Version.from_parts(release=(0,1,0), pre=("b", 1))
|
| 475 |
+
<Version('0.1.0b1')>
|
| 476 |
+
|
| 477 |
+
:param epoch:
|
| 478 |
+
:param release: This version tuple is required
|
| 479 |
+
|
| 480 |
+
.. versionadded:: 26.1
|
| 481 |
+
"""
|
| 482 |
+
_epoch = _validate_epoch(epoch)
|
| 483 |
+
_release = _validate_release(release)
|
| 484 |
+
_pre = _validate_pre(pre) if pre is not None else None
|
| 485 |
+
_post = _validate_post(post) if post is not None else None
|
| 486 |
+
_dev = _validate_dev(dev) if dev is not None else None
|
| 487 |
+
_local = _validate_local(local) if local is not None else None
|
| 488 |
+
|
| 489 |
+
new_version = cls.__new__(cls)
|
| 490 |
+
new_version._key_cache = None
|
| 491 |
+
new_version._hash_cache = None
|
| 492 |
+
new_version._epoch = _epoch
|
| 493 |
+
new_version._release = _release
|
| 494 |
+
new_version._pre = _pre
|
| 495 |
+
new_version._post = _post
|
| 496 |
+
new_version._dev = _dev
|
| 497 |
+
new_version._local = _local
|
| 498 |
+
|
| 499 |
+
return new_version
|
| 500 |
+
|
| 501 |
+
def __replace__(self, **kwargs: Unpack[_VersionReplace]) -> Self:
|
| 502 |
+
"""
|
| 503 |
+
__replace__(*, epoch=..., release=..., pre=..., post=..., dev=..., local=...)
|
| 504 |
+
|
| 505 |
+
Return a new version with parts replaced.
|
| 506 |
+
|
| 507 |
+
This returns a new version (unless no parts were changed). The
|
| 508 |
+
pre-release is normalized. Setting a value to ``None`` clears it.
|
| 509 |
+
|
| 510 |
+
>>> v = Version("1.2.3")
|
| 511 |
+
>>> v.__replace__(pre=("a", 1))
|
| 512 |
+
<Version('1.2.3a1')>
|
| 513 |
+
|
| 514 |
+
:param int | None epoch:
|
| 515 |
+
:param tuple[int, ...] | None release:
|
| 516 |
+
:param tuple[str, int] | None pre:
|
| 517 |
+
:param int | None post:
|
| 518 |
+
:param int | None dev:
|
| 519 |
+
:param str | None local:
|
| 520 |
+
|
| 521 |
+
.. versionadded:: 26.0
|
| 522 |
+
.. versionchanged:: 26.1
|
| 523 |
+
|
| 524 |
+
The pre-release portion is now normalized.
|
| 525 |
+
"""
|
| 526 |
+
epoch = _validate_epoch(kwargs["epoch"]) if "epoch" in kwargs else self._epoch
|
| 527 |
+
release = (
|
| 528 |
+
_validate_release(kwargs["release"])
|
| 529 |
+
if "release" in kwargs
|
| 530 |
+
else self._release
|
| 531 |
+
)
|
| 532 |
+
pre = _validate_pre(kwargs["pre"]) if "pre" in kwargs else self._pre
|
| 533 |
+
post = _validate_post(kwargs["post"]) if "post" in kwargs else self._post
|
| 534 |
+
dev = _validate_dev(kwargs["dev"]) if "dev" in kwargs else self._dev
|
| 535 |
+
local = _validate_local(kwargs["local"]) if "local" in kwargs else self._local
|
| 536 |
+
|
| 537 |
+
if (
|
| 538 |
+
epoch == self._epoch
|
| 539 |
+
and release == self._release
|
| 540 |
+
and pre == self._pre
|
| 541 |
+
and post == self._post
|
| 542 |
+
and dev == self._dev
|
| 543 |
+
and local == self._local
|
| 544 |
+
):
|
| 545 |
+
return self
|
| 546 |
+
|
| 547 |
+
new_version = self.__class__.__new__(self.__class__)
|
| 548 |
+
new_version._key_cache = None
|
| 549 |
+
new_version._hash_cache = None
|
| 550 |
+
new_version._epoch = epoch
|
| 551 |
+
new_version._release = release
|
| 552 |
+
new_version._pre = pre
|
| 553 |
+
new_version._post = post
|
| 554 |
+
new_version._dev = dev
|
| 555 |
+
new_version._local = local
|
| 556 |
+
|
| 557 |
+
return new_version
|
| 558 |
+
|
| 559 |
+
@property
|
| 560 |
+
def _key(self) -> CmpKey:
|
| 561 |
+
if self._key_cache is None:
|
| 562 |
+
self._key_cache = _cmpkey(
|
| 563 |
+
self._epoch,
|
| 564 |
+
self._release,
|
| 565 |
+
self._pre,
|
| 566 |
+
self._post,
|
| 567 |
+
self._dev,
|
| 568 |
+
self._local,
|
| 569 |
+
)
|
| 570 |
+
return self._key_cache
|
| 571 |
+
|
| 572 |
+
# __hash__ must be defined when __eq__ is overridden,
|
| 573 |
+
# otherwise Python sets __hash__ to None.
|
| 574 |
+
def __hash__(self) -> int:
|
| 575 |
+
if (cached_hash := self._hash_cache) is not None:
|
| 576 |
+
return cached_hash
|
| 577 |
+
|
| 578 |
+
if (key := self._key_cache) is None:
|
| 579 |
+
self._key_cache = key = _cmpkey(
|
| 580 |
+
self._epoch,
|
| 581 |
+
self._release,
|
| 582 |
+
self._pre,
|
| 583 |
+
self._post,
|
| 584 |
+
self._dev,
|
| 585 |
+
self._local,
|
| 586 |
+
)
|
| 587 |
+
self._hash_cache = cached_hash = hash(key)
|
| 588 |
+
return cached_hash
|
| 589 |
+
|
| 590 |
+
# Override comparison methods to use direct _key_cache access
|
| 591 |
+
# This is faster than property access, especially before Python 3.12
|
| 592 |
+
def __lt__(self, other: _BaseVersion) -> bool:
|
| 593 |
+
if isinstance(other, Version):
|
| 594 |
+
if self._key_cache is None:
|
| 595 |
+
self._key_cache = _cmpkey(
|
| 596 |
+
self._epoch,
|
| 597 |
+
self._release,
|
| 598 |
+
self._pre,
|
| 599 |
+
self._post,
|
| 600 |
+
self._dev,
|
| 601 |
+
self._local,
|
| 602 |
+
)
|
| 603 |
+
if other._key_cache is None:
|
| 604 |
+
other._key_cache = _cmpkey(
|
| 605 |
+
other._epoch,
|
| 606 |
+
other._release,
|
| 607 |
+
other._pre,
|
| 608 |
+
other._post,
|
| 609 |
+
other._dev,
|
| 610 |
+
other._local,
|
| 611 |
+
)
|
| 612 |
+
return self._key_cache < other._key_cache
|
| 613 |
+
|
| 614 |
+
if not isinstance(other, _BaseVersion):
|
| 615 |
+
return NotImplemented
|
| 616 |
+
|
| 617 |
+
return super().__lt__(other)
|
| 618 |
+
|
| 619 |
+
def __le__(self, other: _BaseVersion) -> bool:
|
| 620 |
+
if isinstance(other, Version):
|
| 621 |
+
if self._key_cache is None:
|
| 622 |
+
self._key_cache = _cmpkey(
|
| 623 |
+
self._epoch,
|
| 624 |
+
self._release,
|
| 625 |
+
self._pre,
|
| 626 |
+
self._post,
|
| 627 |
+
self._dev,
|
| 628 |
+
self._local,
|
| 629 |
+
)
|
| 630 |
+
if other._key_cache is None:
|
| 631 |
+
other._key_cache = _cmpkey(
|
| 632 |
+
other._epoch,
|
| 633 |
+
other._release,
|
| 634 |
+
other._pre,
|
| 635 |
+
other._post,
|
| 636 |
+
other._dev,
|
| 637 |
+
other._local,
|
| 638 |
+
)
|
| 639 |
+
return self._key_cache <= other._key_cache
|
| 640 |
+
|
| 641 |
+
if not isinstance(other, _BaseVersion):
|
| 642 |
+
return NotImplemented
|
| 643 |
+
|
| 644 |
+
return super().__le__(other)
|
| 645 |
+
|
| 646 |
+
def __eq__(self, other: object) -> bool:
|
| 647 |
+
if isinstance(other, Version):
|
| 648 |
+
if self._key_cache is None:
|
| 649 |
+
self._key_cache = _cmpkey(
|
| 650 |
+
self._epoch,
|
| 651 |
+
self._release,
|
| 652 |
+
self._pre,
|
| 653 |
+
self._post,
|
| 654 |
+
self._dev,
|
| 655 |
+
self._local,
|
| 656 |
+
)
|
| 657 |
+
if other._key_cache is None:
|
| 658 |
+
other._key_cache = _cmpkey(
|
| 659 |
+
other._epoch,
|
| 660 |
+
other._release,
|
| 661 |
+
other._pre,
|
| 662 |
+
other._post,
|
| 663 |
+
other._dev,
|
| 664 |
+
other._local,
|
| 665 |
+
)
|
| 666 |
+
return self._key_cache == other._key_cache
|
| 667 |
+
|
| 668 |
+
if not isinstance(other, _BaseVersion):
|
| 669 |
+
return NotImplemented
|
| 670 |
+
|
| 671 |
+
return super().__eq__(other)
|
| 672 |
+
|
| 673 |
+
def __ge__(self, other: _BaseVersion) -> bool:
|
| 674 |
+
if isinstance(other, Version):
|
| 675 |
+
if self._key_cache is None:
|
| 676 |
+
self._key_cache = _cmpkey(
|
| 677 |
+
self._epoch,
|
| 678 |
+
self._release,
|
| 679 |
+
self._pre,
|
| 680 |
+
self._post,
|
| 681 |
+
self._dev,
|
| 682 |
+
self._local,
|
| 683 |
+
)
|
| 684 |
+
if other._key_cache is None:
|
| 685 |
+
other._key_cache = _cmpkey(
|
| 686 |
+
other._epoch,
|
| 687 |
+
other._release,
|
| 688 |
+
other._pre,
|
| 689 |
+
other._post,
|
| 690 |
+
other._dev,
|
| 691 |
+
other._local,
|
| 692 |
+
)
|
| 693 |
+
return self._key_cache >= other._key_cache
|
| 694 |
+
|
| 695 |
+
if not isinstance(other, _BaseVersion):
|
| 696 |
+
return NotImplemented
|
| 697 |
+
|
| 698 |
+
return super().__ge__(other)
|
| 699 |
+
|
| 700 |
+
def __gt__(self, other: _BaseVersion) -> bool:
|
| 701 |
+
if isinstance(other, Version):
|
| 702 |
+
if self._key_cache is None:
|
| 703 |
+
self._key_cache = _cmpkey(
|
| 704 |
+
self._epoch,
|
| 705 |
+
self._release,
|
| 706 |
+
self._pre,
|
| 707 |
+
self._post,
|
| 708 |
+
self._dev,
|
| 709 |
+
self._local,
|
| 710 |
+
)
|
| 711 |
+
if other._key_cache is None:
|
| 712 |
+
other._key_cache = _cmpkey(
|
| 713 |
+
other._epoch,
|
| 714 |
+
other._release,
|
| 715 |
+
other._pre,
|
| 716 |
+
other._post,
|
| 717 |
+
other._dev,
|
| 718 |
+
other._local,
|
| 719 |
+
)
|
| 720 |
+
return self._key_cache > other._key_cache
|
| 721 |
+
|
| 722 |
+
if not isinstance(other, _BaseVersion):
|
| 723 |
+
return NotImplemented
|
| 724 |
+
|
| 725 |
+
return super().__gt__(other)
|
| 726 |
+
|
| 727 |
+
def __ne__(self, other: object) -> bool:
|
| 728 |
+
if isinstance(other, Version):
|
| 729 |
+
if self._key_cache is None:
|
| 730 |
+
self._key_cache = _cmpkey(
|
| 731 |
+
self._epoch,
|
| 732 |
+
self._release,
|
| 733 |
+
self._pre,
|
| 734 |
+
self._post,
|
| 735 |
+
self._dev,
|
| 736 |
+
self._local,
|
| 737 |
+
)
|
| 738 |
+
if other._key_cache is None:
|
| 739 |
+
other._key_cache = _cmpkey(
|
| 740 |
+
other._epoch,
|
| 741 |
+
other._release,
|
| 742 |
+
other._pre,
|
| 743 |
+
other._post,
|
| 744 |
+
other._dev,
|
| 745 |
+
other._local,
|
| 746 |
+
)
|
| 747 |
+
return self._key_cache != other._key_cache
|
| 748 |
+
|
| 749 |
+
if not isinstance(other, _BaseVersion):
|
| 750 |
+
return NotImplemented
|
| 751 |
+
|
| 752 |
+
return super().__ne__(other)
|
| 753 |
+
|
| 754 |
+
def __getstate__(
|
| 755 |
+
self,
|
| 756 |
+
) -> tuple[
|
| 757 |
+
int,
|
| 758 |
+
tuple[int, ...],
|
| 759 |
+
tuple[str, int] | None,
|
| 760 |
+
tuple[str, int] | None,
|
| 761 |
+
tuple[str, int] | None,
|
| 762 |
+
LocalType | None,
|
| 763 |
+
]:
|
| 764 |
+
# Return state as a 6-item tuple for compactness:
|
| 765 |
+
# (epoch, release, pre, post, dev, local)
|
| 766 |
+
# Cache members are excluded and will be recomputed on demand
|
| 767 |
+
return (
|
| 768 |
+
self._epoch,
|
| 769 |
+
self._release,
|
| 770 |
+
self._pre,
|
| 771 |
+
self._post,
|
| 772 |
+
self._dev,
|
| 773 |
+
self._local,
|
| 774 |
+
)
|
| 775 |
+
|
| 776 |
+
def __setstate__(self, state: object) -> None:
|
| 777 |
+
# Always discard cached values — they may contain stale references
|
| 778 |
+
# (e.g. packaging._structures.InfinityType from pre-26.1 pickles)
|
| 779 |
+
# and will be recomputed on demand from the core fields above.
|
| 780 |
+
self._key_cache = None
|
| 781 |
+
self._hash_cache = None
|
| 782 |
+
|
| 783 |
+
if isinstance(state, tuple):
|
| 784 |
+
if len(state) == 6:
|
| 785 |
+
# New format (26.2+): (epoch, release, pre, post, dev, local)
|
| 786 |
+
(
|
| 787 |
+
self._epoch,
|
| 788 |
+
self._release,
|
| 789 |
+
self._pre,
|
| 790 |
+
self._post,
|
| 791 |
+
self._dev,
|
| 792 |
+
self._local,
|
| 793 |
+
) = state
|
| 794 |
+
return
|
| 795 |
+
if len(state) == 2:
|
| 796 |
+
# Format (packaging 26.0-26.1): (None, {slot: value}).
|
| 797 |
+
_, slot_dict = state
|
| 798 |
+
if isinstance(slot_dict, dict):
|
| 799 |
+
self._epoch = slot_dict["_epoch"]
|
| 800 |
+
self._release = slot_dict["_release"]
|
| 801 |
+
self._pre = slot_dict.get("_pre")
|
| 802 |
+
self._post = slot_dict.get("_post")
|
| 803 |
+
self._dev = slot_dict.get("_dev")
|
| 804 |
+
self._local = slot_dict.get("_local")
|
| 805 |
+
return
|
| 806 |
+
if isinstance(state, dict):
|
| 807 |
+
# Old format (packaging <= 25.x, no __slots__): state is a plain
|
| 808 |
+
# dict with "_version" (_Version NamedTuple) and "_key" entries.
|
| 809 |
+
version_nt = state.get("_version")
|
| 810 |
+
if version_nt is not None:
|
| 811 |
+
self._epoch = version_nt.epoch
|
| 812 |
+
self._release = version_nt.release
|
| 813 |
+
self._pre = version_nt.pre
|
| 814 |
+
self._post = version_nt.post
|
| 815 |
+
self._dev = version_nt.dev
|
| 816 |
+
self._local = version_nt.local
|
| 817 |
+
return
|
| 818 |
+
|
| 819 |
+
raise TypeError(f"Cannot restore Version from {state!r}")
|
| 820 |
+
|
| 821 |
+
@property
|
| 822 |
+
@_deprecated("Version._version is private and will be removed soon")
|
| 823 |
+
def _version(self) -> _Version:
|
| 824 |
+
return _Version(
|
| 825 |
+
self._epoch, self._release, self._dev, self._pre, self._post, self._local
|
| 826 |
+
)
|
| 827 |
+
|
| 828 |
+
@_version.setter
|
| 829 |
+
@_deprecated("Version._version is private and will be removed soon")
|
| 830 |
+
def _version(self, value: _Version) -> None:
|
| 831 |
+
self._epoch = value.epoch
|
| 832 |
+
self._release = value.release
|
| 833 |
+
self._dev = value.dev
|
| 834 |
+
self._pre = value.pre
|
| 835 |
+
self._post = value.post
|
| 836 |
+
self._local = value.local
|
| 837 |
+
self._key_cache = None
|
| 838 |
+
self._hash_cache = None
|
| 839 |
+
|
| 840 |
+
def __repr__(self) -> str:
|
| 841 |
+
"""A representation of the Version that shows all internal state.
|
| 842 |
+
|
| 843 |
+
>>> Version('1.0.0')
|
| 844 |
+
<Version('1.0.0')>
|
| 845 |
+
"""
|
| 846 |
+
return f"<{self.__class__.__name__}({str(self)!r})>"
|
| 847 |
+
|
| 848 |
+
def __str__(self) -> str:
|
| 849 |
+
"""A string representation of the version that can be round-tripped.
|
| 850 |
+
|
| 851 |
+
>>> str(Version("1.0a5"))
|
| 852 |
+
'1.0a5'
|
| 853 |
+
"""
|
| 854 |
+
# This is a hot function, so not calling self.base_version
|
| 855 |
+
version = ".".join(map(str, self.release))
|
| 856 |
+
|
| 857 |
+
# Epoch
|
| 858 |
+
if self.epoch:
|
| 859 |
+
version = f"{self.epoch}!{version}"
|
| 860 |
+
|
| 861 |
+
# Pre-release
|
| 862 |
+
if self.pre is not None:
|
| 863 |
+
version += "".join(map(str, self.pre))
|
| 864 |
+
|
| 865 |
+
# Post-release
|
| 866 |
+
if self.post is not None:
|
| 867 |
+
version += f".post{self.post}"
|
| 868 |
+
|
| 869 |
+
# Development release
|
| 870 |
+
if self.dev is not None:
|
| 871 |
+
version += f".dev{self.dev}"
|
| 872 |
+
|
| 873 |
+
# Local version segment
|
| 874 |
+
if self.local is not None:
|
| 875 |
+
version += f"+{self.local}"
|
| 876 |
+
|
| 877 |
+
return version
|
| 878 |
+
|
| 879 |
+
@property
|
| 880 |
+
def _str(self) -> str:
|
| 881 |
+
"""Internal property for match_args"""
|
| 882 |
+
return str(self)
|
| 883 |
+
|
| 884 |
+
@property
|
| 885 |
+
def epoch(self) -> int:
|
| 886 |
+
"""The epoch of the version.
|
| 887 |
+
|
| 888 |
+
>>> Version("2.0.0").epoch
|
| 889 |
+
0
|
| 890 |
+
>>> Version("1!2.0.0").epoch
|
| 891 |
+
1
|
| 892 |
+
"""
|
| 893 |
+
return self._epoch
|
| 894 |
+
|
| 895 |
+
@property
|
| 896 |
+
def release(self) -> tuple[int, ...]:
|
| 897 |
+
"""The components of the "release" segment of the version.
|
| 898 |
+
|
| 899 |
+
>>> Version("1.2.3").release
|
| 900 |
+
(1, 2, 3)
|
| 901 |
+
>>> Version("2.0.0").release
|
| 902 |
+
(2, 0, 0)
|
| 903 |
+
>>> Version("1!2.0.0.post0").release
|
| 904 |
+
(2, 0, 0)
|
| 905 |
+
|
| 906 |
+
Includes trailing zeroes but not the epoch or any pre-release / development /
|
| 907 |
+
post-release suffixes.
|
| 908 |
+
"""
|
| 909 |
+
return self._release
|
| 910 |
+
|
| 911 |
+
@property
|
| 912 |
+
def pre(self) -> tuple[Literal["a", "b", "rc"], int] | None:
|
| 913 |
+
"""The pre-release segment of the version.
|
| 914 |
+
|
| 915 |
+
>>> print(Version("1.2.3").pre)
|
| 916 |
+
None
|
| 917 |
+
>>> Version("1.2.3a1").pre
|
| 918 |
+
('a', 1)
|
| 919 |
+
>>> Version("1.2.3b1").pre
|
| 920 |
+
('b', 1)
|
| 921 |
+
>>> Version("1.2.3rc1").pre
|
| 922 |
+
('rc', 1)
|
| 923 |
+
"""
|
| 924 |
+
return self._pre
|
| 925 |
+
|
| 926 |
+
@property
|
| 927 |
+
def post(self) -> int | None:
|
| 928 |
+
"""The post-release number of the version.
|
| 929 |
+
|
| 930 |
+
>>> print(Version("1.2.3").post)
|
| 931 |
+
None
|
| 932 |
+
>>> Version("1.2.3.post1").post
|
| 933 |
+
1
|
| 934 |
+
"""
|
| 935 |
+
return self._post[1] if self._post else None
|
| 936 |
+
|
| 937 |
+
@property
|
| 938 |
+
def dev(self) -> int | None:
|
| 939 |
+
"""The development number of the version.
|
| 940 |
+
|
| 941 |
+
>>> print(Version("1.2.3").dev)
|
| 942 |
+
None
|
| 943 |
+
>>> Version("1.2.3.dev1").dev
|
| 944 |
+
1
|
| 945 |
+
"""
|
| 946 |
+
return self._dev[1] if self._dev else None
|
| 947 |
+
|
| 948 |
+
@property
|
| 949 |
+
def local(self) -> str | None:
|
| 950 |
+
"""The local version segment of the version.
|
| 951 |
+
|
| 952 |
+
>>> print(Version("1.2.3").local)
|
| 953 |
+
None
|
| 954 |
+
>>> Version("1.2.3+abc").local
|
| 955 |
+
'abc'
|
| 956 |
+
"""
|
| 957 |
+
if self._local:
|
| 958 |
+
return ".".join(str(x) for x in self._local)
|
| 959 |
+
else:
|
| 960 |
+
return None
|
| 961 |
+
|
| 962 |
+
@property
|
| 963 |
+
def public(self) -> str:
|
| 964 |
+
"""The public portion of the version.
|
| 965 |
+
|
| 966 |
+
This returns a string. If you want a :class:`Version` again and care
|
| 967 |
+
about performance, use ``v.__replace__(local=None)`` instead.
|
| 968 |
+
|
| 969 |
+
>>> Version("1.2.3").public
|
| 970 |
+
'1.2.3'
|
| 971 |
+
>>> Version("1.2.3+abc").public
|
| 972 |
+
'1.2.3'
|
| 973 |
+
>>> Version("1!1.2.3dev1+abc").public
|
| 974 |
+
'1!1.2.3.dev1'
|
| 975 |
+
"""
|
| 976 |
+
return str(self).split("+", 1)[0]
|
| 977 |
+
|
| 978 |
+
@property
|
| 979 |
+
def base_version(self) -> str:
|
| 980 |
+
"""The "base version" of the version.
|
| 981 |
+
|
| 982 |
+
This returns a string. If you want a :class:`Version` again and care
|
| 983 |
+
about performance, use
|
| 984 |
+
``v.__replace__(pre=None, post=None, dev=None, local=None)`` instead.
|
| 985 |
+
|
| 986 |
+
>>> Version("1.2.3").base_version
|
| 987 |
+
'1.2.3'
|
| 988 |
+
>>> Version("1.2.3+abc").base_version
|
| 989 |
+
'1.2.3'
|
| 990 |
+
>>> Version("1!1.2.3dev1+abc").base_version
|
| 991 |
+
'1!1.2.3'
|
| 992 |
+
|
| 993 |
+
The "base version" is the public version of the project without any pre or post
|
| 994 |
+
release markers.
|
| 995 |
+
"""
|
| 996 |
+
release_segment = ".".join(map(str, self.release))
|
| 997 |
+
return f"{self.epoch}!{release_segment}" if self.epoch else release_segment
|
| 998 |
+
|
| 999 |
+
@property
|
| 1000 |
+
def is_prerelease(self) -> bool:
|
| 1001 |
+
"""Whether this version is a pre-release.
|
| 1002 |
+
|
| 1003 |
+
>>> Version("1.2.3").is_prerelease
|
| 1004 |
+
False
|
| 1005 |
+
>>> Version("1.2.3a1").is_prerelease
|
| 1006 |
+
True
|
| 1007 |
+
>>> Version("1.2.3b1").is_prerelease
|
| 1008 |
+
True
|
| 1009 |
+
>>> Version("1.2.3rc1").is_prerelease
|
| 1010 |
+
True
|
| 1011 |
+
>>> Version("1.2.3dev1").is_prerelease
|
| 1012 |
+
True
|
| 1013 |
+
"""
|
| 1014 |
+
return self.dev is not None or self.pre is not None
|
| 1015 |
+
|
| 1016 |
+
@property
|
| 1017 |
+
def is_postrelease(self) -> bool:
|
| 1018 |
+
"""Whether this version is a post-release.
|
| 1019 |
+
|
| 1020 |
+
>>> Version("1.2.3").is_postrelease
|
| 1021 |
+
False
|
| 1022 |
+
>>> Version("1.2.3.post1").is_postrelease
|
| 1023 |
+
True
|
| 1024 |
+
"""
|
| 1025 |
+
return self.post is not None
|
| 1026 |
+
|
| 1027 |
+
@property
|
| 1028 |
+
def is_devrelease(self) -> bool:
|
| 1029 |
+
"""Whether this version is a development release.
|
| 1030 |
+
|
| 1031 |
+
>>> Version("1.2.3").is_devrelease
|
| 1032 |
+
False
|
| 1033 |
+
>>> Version("1.2.3.dev1").is_devrelease
|
| 1034 |
+
True
|
| 1035 |
+
"""
|
| 1036 |
+
return self.dev is not None
|
| 1037 |
+
|
| 1038 |
+
@property
|
| 1039 |
+
def major(self) -> int:
|
| 1040 |
+
"""The first item of :attr:`release` or ``0`` if unavailable.
|
| 1041 |
+
|
| 1042 |
+
>>> Version("1.2.3").major
|
| 1043 |
+
1
|
| 1044 |
+
"""
|
| 1045 |
+
return self.release[0] if len(self.release) >= 1 else 0
|
| 1046 |
+
|
| 1047 |
+
@property
|
| 1048 |
+
def minor(self) -> int:
|
| 1049 |
+
"""The second item of :attr:`release` or ``0`` if unavailable.
|
| 1050 |
+
|
| 1051 |
+
>>> Version("1.2.3").minor
|
| 1052 |
+
2
|
| 1053 |
+
>>> Version("1").minor
|
| 1054 |
+
0
|
| 1055 |
+
"""
|
| 1056 |
+
return self.release[1] if len(self.release) >= 2 else 0
|
| 1057 |
+
|
| 1058 |
+
@property
|
| 1059 |
+
def micro(self) -> int:
|
| 1060 |
+
"""The third item of :attr:`release` or ``0`` if unavailable.
|
| 1061 |
+
|
| 1062 |
+
>>> Version("1.2.3").micro
|
| 1063 |
+
3
|
| 1064 |
+
>>> Version("1").micro
|
| 1065 |
+
0
|
| 1066 |
+
"""
|
| 1067 |
+
return self.release[2] if len(self.release) >= 3 else 0
|
| 1068 |
+
|
| 1069 |
+
|
| 1070 |
+
class _TrimmedRelease(Version):
|
| 1071 |
+
__slots__ = ()
|
| 1072 |
+
|
| 1073 |
+
def __init__(self, version: str | Version) -> None:
|
| 1074 |
+
if isinstance(version, Version):
|
| 1075 |
+
self._epoch = version._epoch
|
| 1076 |
+
self._release = version._release
|
| 1077 |
+
self._dev = version._dev
|
| 1078 |
+
self._pre = version._pre
|
| 1079 |
+
self._post = version._post
|
| 1080 |
+
self._local = version._local
|
| 1081 |
+
self._key_cache = version._key_cache
|
| 1082 |
+
return
|
| 1083 |
+
super().__init__(version) # pragma: no cover
|
| 1084 |
+
|
| 1085 |
+
@property
|
| 1086 |
+
def release(self) -> tuple[int, ...]:
|
| 1087 |
+
"""
|
| 1088 |
+
Release segment without any trailing zeros.
|
| 1089 |
+
|
| 1090 |
+
>>> _TrimmedRelease('1.0.0').release
|
| 1091 |
+
(1,)
|
| 1092 |
+
>>> _TrimmedRelease('0.0').release
|
| 1093 |
+
(0,)
|
| 1094 |
+
"""
|
| 1095 |
+
# This leaves one 0.
|
| 1096 |
+
rel = super().release
|
| 1097 |
+
len_release = len(rel)
|
| 1098 |
+
i = len_release
|
| 1099 |
+
while i > 1 and rel[i - 1] == 0:
|
| 1100 |
+
i -= 1
|
| 1101 |
+
return rel if i == len_release else rel[:i]
|
| 1102 |
+
|
| 1103 |
+
|
| 1104 |
+
def _parse_letter_version(
|
| 1105 |
+
letter: str | None, number: str | bytes | SupportsInt | None
|
| 1106 |
+
) -> tuple[str, int] | None:
|
| 1107 |
+
if letter:
|
| 1108 |
+
# We normalize any letters to their lower case form
|
| 1109 |
+
letter = letter.lower()
|
| 1110 |
+
|
| 1111 |
+
# We consider some words to be alternate spellings of other words and
|
| 1112 |
+
# in those cases we want to normalize the spellings to our preferred
|
| 1113 |
+
# spelling.
|
| 1114 |
+
letter = _LETTER_NORMALIZATION.get(letter, letter)
|
| 1115 |
+
|
| 1116 |
+
# We consider there to be an implicit 0 in a pre-release if there is
|
| 1117 |
+
# not a numeral associated with it.
|
| 1118 |
+
return letter, int(number or 0)
|
| 1119 |
+
|
| 1120 |
+
if number:
|
| 1121 |
+
# We assume if we are given a number, but we are not given a letter
|
| 1122 |
+
# then this is using the implicit post release syntax (e.g. 1.0-1)
|
| 1123 |
+
return "post", int(number)
|
| 1124 |
+
|
| 1125 |
+
return None
|
| 1126 |
+
|
| 1127 |
+
|
| 1128 |
+
_local_version_separators = re.compile(r"[\._-]")
|
| 1129 |
+
|
| 1130 |
+
|
| 1131 |
+
def _parse_local_version(local: str | None) -> LocalType | None:
|
| 1132 |
+
"""
|
| 1133 |
+
Takes a string like ``"abc.1.twelve"`` and turns it into
|
| 1134 |
+
``("abc", 1, "twelve")``.
|
| 1135 |
+
"""
|
| 1136 |
+
if local is not None:
|
| 1137 |
+
return tuple(
|
| 1138 |
+
part.lower() if not part.isdigit() else int(part)
|
| 1139 |
+
for part in _local_version_separators.split(local)
|
| 1140 |
+
)
|
| 1141 |
+
return None
|
| 1142 |
+
|
| 1143 |
+
|
| 1144 |
+
# Sort ranks for pre-release: dev-only < a < b < rc < stable (no pre-release).
|
| 1145 |
+
_PRE_RANK = {"a": 0, "b": 1, "rc": 2}
|
| 1146 |
+
_PRE_RANK_DEV_ONLY = -1 # sorts before a(0)
|
| 1147 |
+
_PRE_RANK_STABLE = 3 # sorts after rc(2)
|
| 1148 |
+
|
| 1149 |
+
# In local version segments, strings sort before ints per PEP 440.
|
| 1150 |
+
_LOCAL_STR_RANK = -1 # sorts before all non-negative ints
|
| 1151 |
+
|
| 1152 |
+
# Pre-computed suffix for stable releases (no pre, post, or dev segments).
|
| 1153 |
+
# See _cmpkey() for the suffix layout.
|
| 1154 |
+
_STABLE_SUFFIX = (_PRE_RANK_STABLE, 0, 0, 0, 1, 0)
|
| 1155 |
+
|
| 1156 |
+
|
| 1157 |
+
def _cmpkey(
|
| 1158 |
+
epoch: int,
|
| 1159 |
+
release: tuple[int, ...],
|
| 1160 |
+
pre: tuple[str, int] | None,
|
| 1161 |
+
post: tuple[str, int] | None,
|
| 1162 |
+
dev: tuple[str, int] | None,
|
| 1163 |
+
local: LocalType | None,
|
| 1164 |
+
) -> CmpKey:
|
| 1165 |
+
"""Build a comparison key for PEP 440 ordering.
|
| 1166 |
+
|
| 1167 |
+
Returns ``(epoch, release, suffix)`` or
|
| 1168 |
+
``(epoch, release, suffix, local)`` so that plain tuple
|
| 1169 |
+
comparison gives the correct order.
|
| 1170 |
+
|
| 1171 |
+
Trailing zeros are stripped from the release so that ``1.0.0 == 1``.
|
| 1172 |
+
|
| 1173 |
+
The suffix is a flat 6-int tuple that encodes pre/post/dev:
|
| 1174 |
+
``(pre_rank, pre_n, post_rank, post_n, dev_rank, dev_n)``
|
| 1175 |
+
|
| 1176 |
+
pre_rank: dev-only=-1, a=0, b=1, rc=2, no-pre=3
|
| 1177 |
+
Dev-only releases (no pre or post) get -1 so they sort before
|
| 1178 |
+
any alpha/beta/rc. Releases without a pre-release tag get 3
|
| 1179 |
+
so they sort after rc.
|
| 1180 |
+
post_rank: no-post=0, post=1
|
| 1181 |
+
Releases without a post segment sort before those with one.
|
| 1182 |
+
dev_rank: dev=0, no-dev=1
|
| 1183 |
+
Releases without a dev segment sort after those with one.
|
| 1184 |
+
|
| 1185 |
+
Local segments use ``(n, "")`` for ints and ``(-1, s)`` for strings,
|
| 1186 |
+
following PEP 440: strings sort before ints, strings compare
|
| 1187 |
+
lexicographically, ints compare numerically, and shorter segments
|
| 1188 |
+
sort before longer when prefixes match. Versions without a local
|
| 1189 |
+
segment sort before those with one (3-tuple < 4-tuple).
|
| 1190 |
+
|
| 1191 |
+
>>> _cmpkey(0, (1, 0, 0), None, None, None, None)
|
| 1192 |
+
(0, (1,), (3, 0, 0, 0, 1, 0))
|
| 1193 |
+
>>> _cmpkey(0, (1,), ("a", 1), None, None, None)
|
| 1194 |
+
(0, (1,), (0, 1, 0, 0, 1, 0))
|
| 1195 |
+
>>> _cmpkey(0, (1,), None, None, None, ("ubuntu", 1))
|
| 1196 |
+
(0, (1,), (3, 0, 0, 0, 1, 0), ((-1, 'ubuntu'), (1, '')))
|
| 1197 |
+
"""
|
| 1198 |
+
# Strip trailing zeros: 1.0.0 compares equal to 1.
|
| 1199 |
+
len_release = len(release)
|
| 1200 |
+
i = len_release
|
| 1201 |
+
while i and release[i - 1] == 0:
|
| 1202 |
+
i -= 1
|
| 1203 |
+
trimmed = release if i == len_release else release[:i]
|
| 1204 |
+
|
| 1205 |
+
# Fast path: stable release with no local segment.
|
| 1206 |
+
if pre is None and post is None and dev is None and local is None:
|
| 1207 |
+
return epoch, trimmed, _STABLE_SUFFIX
|
| 1208 |
+
|
| 1209 |
+
if pre is None and post is None and dev is not None:
|
| 1210 |
+
# dev-only (e.g. 1.0.dev1) sorts before all pre-releases.
|
| 1211 |
+
pre_rank, pre_n = _PRE_RANK_DEV_ONLY, 0
|
| 1212 |
+
elif pre is None:
|
| 1213 |
+
pre_rank, pre_n = _PRE_RANK_STABLE, 0
|
| 1214 |
+
else:
|
| 1215 |
+
pre_rank, pre_n = _PRE_RANK[pre[0]], pre[1]
|
| 1216 |
+
|
| 1217 |
+
post_rank = 0 if post is None else 1
|
| 1218 |
+
post_n = 0 if post is None else post[1]
|
| 1219 |
+
|
| 1220 |
+
dev_rank = 1 if dev is None else 0
|
| 1221 |
+
dev_n = 0 if dev is None else dev[1]
|
| 1222 |
+
|
| 1223 |
+
suffix = (pre_rank, pre_n, post_rank, post_n, dev_rank, dev_n)
|
| 1224 |
+
|
| 1225 |
+
if local is None:
|
| 1226 |
+
return epoch, trimmed, suffix
|
| 1227 |
+
|
| 1228 |
+
cmp_local: CmpLocalType = tuple(
|
| 1229 |
+
(seg, "") if isinstance(seg, int) else (_LOCAL_STR_RANK, seg) for seg in local
|
| 1230 |
+
)
|
| 1231 |
+
return epoch, trimmed, suffix, cmp_local
|
.venv/lib/python3.14/site-packages/pip/_vendor/pkg_resources/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 2 |
+
of this software and associated documentation files (the "Software"), to
|
| 3 |
+
deal in the Software without restriction, including without limitation the
|
| 4 |
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
| 5 |
+
sell copies of the Software, and to permit persons to whom the Software is
|
| 6 |
+
furnished to do so, subject to the following conditions:
|
| 7 |
+
|
| 8 |
+
The above copyright notice and this permission notice shall be included in
|
| 9 |
+
all copies or substantial portions of the Software.
|
| 10 |
+
|
| 11 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 12 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 13 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 14 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 15 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
| 16 |
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
| 17 |
+
IN THE SOFTWARE.
|
.venv/lib/python3.14/site-packages/pip/_vendor/pkg_resources/__init__.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
.venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2010-202x The platformdirs developers
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
.venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/__init__.py
ADDED
|
@@ -0,0 +1,917 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Utilities for determining application-specific dirs.
|
| 2 |
+
|
| 3 |
+
Provides convenience functions (e.g. :func:`user_data_dir`, :func:`user_config_path`), a :data:`PlatformDirs` class that
|
| 4 |
+
auto-detects the current platform, and the :class:`~platformdirs.api.PlatformDirsABC` base class.
|
| 5 |
+
|
| 6 |
+
See <https://github.com/platformdirs/platformdirs> for details and usage.
|
| 7 |
+
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
from __future__ import annotations
|
| 11 |
+
|
| 12 |
+
import os
|
| 13 |
+
import sys
|
| 14 |
+
from typing import TYPE_CHECKING
|
| 15 |
+
|
| 16 |
+
from .api import PlatformDirsABC
|
| 17 |
+
from .version import __version__
|
| 18 |
+
from .version import __version_tuple__ as __version_info__
|
| 19 |
+
|
| 20 |
+
if TYPE_CHECKING:
|
| 21 |
+
from pathlib import Path
|
| 22 |
+
from typing import Literal
|
| 23 |
+
|
| 24 |
+
if sys.platform == "win32":
|
| 25 |
+
from pip._vendor.platformdirs.windows import Windows as _Result
|
| 26 |
+
elif sys.platform == "darwin":
|
| 27 |
+
from pip._vendor.platformdirs.macos import MacOS as _Result
|
| 28 |
+
else:
|
| 29 |
+
from pip._vendor.platformdirs.unix import Unix as _Result
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def _set_platform_dir_class() -> type[PlatformDirsABC]:
|
| 33 |
+
if os.getenv("ANDROID_DATA") == "/data" and os.getenv("ANDROID_ROOT") == "/system":
|
| 34 |
+
if os.getenv("SHELL") or os.getenv("PREFIX"):
|
| 35 |
+
return _Result
|
| 36 |
+
|
| 37 |
+
from pip._vendor.platformdirs.android import _android_folder # noqa: PLC0415
|
| 38 |
+
|
| 39 |
+
if _android_folder() is not None:
|
| 40 |
+
from pip._vendor.platformdirs.android import Android # noqa: PLC0415
|
| 41 |
+
|
| 42 |
+
return Android # return to avoid redefinition of a result
|
| 43 |
+
|
| 44 |
+
return _Result
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
if TYPE_CHECKING:
|
| 48 |
+
# Work around mypy issue: https://github.com/python/mypy/issues/10962
|
| 49 |
+
PlatformDirs = _Result
|
| 50 |
+
else:
|
| 51 |
+
PlatformDirs = _set_platform_dir_class() #: Currently active platform
|
| 52 |
+
AppDirs = PlatformDirs #: Backwards compatibility with appdirs
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def user_data_dir( # noqa: PLR0913, PLR0917
|
| 56 |
+
appname: str | None = None,
|
| 57 |
+
appauthor: str | Literal[False] | None = None,
|
| 58 |
+
version: str | None = None,
|
| 59 |
+
roaming: bool = False, # noqa: FBT001, FBT002
|
| 60 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 61 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 62 |
+
) -> str:
|
| 63 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 64 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 65 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 66 |
+
:param roaming: See `roaming <platformdirs.api.PlatformDirsABC.roaming>`.
|
| 67 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 68 |
+
:param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
|
| 69 |
+
|
| 70 |
+
:returns: data directory tied to the user
|
| 71 |
+
|
| 72 |
+
"""
|
| 73 |
+
return PlatformDirs(
|
| 74 |
+
appname=appname,
|
| 75 |
+
appauthor=appauthor,
|
| 76 |
+
version=version,
|
| 77 |
+
roaming=roaming,
|
| 78 |
+
ensure_exists=ensure_exists,
|
| 79 |
+
use_site_for_root=use_site_for_root,
|
| 80 |
+
).user_data_dir
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def site_data_dir(
|
| 84 |
+
appname: str | None = None,
|
| 85 |
+
appauthor: str | Literal[False] | None = None,
|
| 86 |
+
version: str | None = None,
|
| 87 |
+
multipath: bool = False, # noqa: FBT001, FBT002
|
| 88 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 89 |
+
) -> str:
|
| 90 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 91 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 92 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 93 |
+
:param multipath: See `multipath <platformdirs.api.PlatformDirsABC.multipath>`.
|
| 94 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 95 |
+
|
| 96 |
+
:returns: data directory shared by users
|
| 97 |
+
|
| 98 |
+
"""
|
| 99 |
+
return PlatformDirs(
|
| 100 |
+
appname=appname,
|
| 101 |
+
appauthor=appauthor,
|
| 102 |
+
version=version,
|
| 103 |
+
multipath=multipath,
|
| 104 |
+
ensure_exists=ensure_exists,
|
| 105 |
+
).site_data_dir
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def user_config_dir( # noqa: PLR0913, PLR0917
|
| 109 |
+
appname: str | None = None,
|
| 110 |
+
appauthor: str | Literal[False] | None = None,
|
| 111 |
+
version: str | None = None,
|
| 112 |
+
roaming: bool = False, # noqa: FBT001, FBT002
|
| 113 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 114 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 115 |
+
) -> str:
|
| 116 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 117 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 118 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 119 |
+
:param roaming: See `roaming <platformdirs.api.PlatformDirsABC.roaming>`.
|
| 120 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 121 |
+
:param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
|
| 122 |
+
|
| 123 |
+
:returns: config directory tied to the user
|
| 124 |
+
|
| 125 |
+
"""
|
| 126 |
+
return PlatformDirs(
|
| 127 |
+
appname=appname,
|
| 128 |
+
appauthor=appauthor,
|
| 129 |
+
version=version,
|
| 130 |
+
roaming=roaming,
|
| 131 |
+
ensure_exists=ensure_exists,
|
| 132 |
+
use_site_for_root=use_site_for_root,
|
| 133 |
+
).user_config_dir
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def site_config_dir(
|
| 137 |
+
appname: str | None = None,
|
| 138 |
+
appauthor: str | Literal[False] | None = None,
|
| 139 |
+
version: str | None = None,
|
| 140 |
+
multipath: bool = False, # noqa: FBT001, FBT002
|
| 141 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 142 |
+
) -> str:
|
| 143 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 144 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 145 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 146 |
+
:param multipath: See `multipath <platformdirs.api.PlatformDirsABC.multipath>`.
|
| 147 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 148 |
+
|
| 149 |
+
:returns: config directory shared by users
|
| 150 |
+
|
| 151 |
+
"""
|
| 152 |
+
return PlatformDirs(
|
| 153 |
+
appname=appname,
|
| 154 |
+
appauthor=appauthor,
|
| 155 |
+
version=version,
|
| 156 |
+
multipath=multipath,
|
| 157 |
+
ensure_exists=ensure_exists,
|
| 158 |
+
).site_config_dir
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
def user_cache_dir( # noqa: PLR0913, PLR0917
|
| 162 |
+
appname: str | None = None,
|
| 163 |
+
appauthor: str | Literal[False] | None = None,
|
| 164 |
+
version: str | None = None,
|
| 165 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 166 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 167 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 168 |
+
) -> str:
|
| 169 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 170 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 171 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 172 |
+
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
|
| 173 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 174 |
+
:param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
|
| 175 |
+
|
| 176 |
+
:returns: cache directory tied to the user
|
| 177 |
+
|
| 178 |
+
"""
|
| 179 |
+
return PlatformDirs(
|
| 180 |
+
appname=appname,
|
| 181 |
+
appauthor=appauthor,
|
| 182 |
+
version=version,
|
| 183 |
+
opinion=opinion,
|
| 184 |
+
ensure_exists=ensure_exists,
|
| 185 |
+
use_site_for_root=use_site_for_root,
|
| 186 |
+
).user_cache_dir
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
def site_cache_dir(
|
| 190 |
+
appname: str | None = None,
|
| 191 |
+
appauthor: str | Literal[False] | None = None,
|
| 192 |
+
version: str | None = None,
|
| 193 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 194 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 195 |
+
) -> str:
|
| 196 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 197 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 198 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 199 |
+
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
|
| 200 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 201 |
+
|
| 202 |
+
:returns: cache directory shared by users
|
| 203 |
+
|
| 204 |
+
"""
|
| 205 |
+
return PlatformDirs(
|
| 206 |
+
appname=appname,
|
| 207 |
+
appauthor=appauthor,
|
| 208 |
+
version=version,
|
| 209 |
+
opinion=opinion,
|
| 210 |
+
ensure_exists=ensure_exists,
|
| 211 |
+
).site_cache_dir
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def user_state_dir( # noqa: PLR0913, PLR0917
|
| 215 |
+
appname: str | None = None,
|
| 216 |
+
appauthor: str | Literal[False] | None = None,
|
| 217 |
+
version: str | None = None,
|
| 218 |
+
roaming: bool = False, # noqa: FBT001, FBT002
|
| 219 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 220 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 221 |
+
) -> str:
|
| 222 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 223 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 224 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 225 |
+
:param roaming: See `roaming <platformdirs.api.PlatformDirsABC.roaming>`.
|
| 226 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 227 |
+
:param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
|
| 228 |
+
|
| 229 |
+
:returns: state directory tied to the user
|
| 230 |
+
|
| 231 |
+
"""
|
| 232 |
+
return PlatformDirs(
|
| 233 |
+
appname=appname,
|
| 234 |
+
appauthor=appauthor,
|
| 235 |
+
version=version,
|
| 236 |
+
roaming=roaming,
|
| 237 |
+
ensure_exists=ensure_exists,
|
| 238 |
+
use_site_for_root=use_site_for_root,
|
| 239 |
+
).user_state_dir
|
| 240 |
+
|
| 241 |
+
|
| 242 |
+
def site_state_dir(
|
| 243 |
+
appname: str | None = None,
|
| 244 |
+
appauthor: str | Literal[False] | None = None,
|
| 245 |
+
version: str | None = None,
|
| 246 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 247 |
+
) -> str:
|
| 248 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 249 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 250 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 251 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 252 |
+
|
| 253 |
+
:returns: state directory shared by users
|
| 254 |
+
|
| 255 |
+
"""
|
| 256 |
+
return PlatformDirs(
|
| 257 |
+
appname=appname,
|
| 258 |
+
appauthor=appauthor,
|
| 259 |
+
version=version,
|
| 260 |
+
ensure_exists=ensure_exists,
|
| 261 |
+
).site_state_dir
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
def user_log_dir( # noqa: PLR0913, PLR0917
|
| 265 |
+
appname: str | None = None,
|
| 266 |
+
appauthor: str | Literal[False] | None = None,
|
| 267 |
+
version: str | None = None,
|
| 268 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 269 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 270 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 271 |
+
) -> str:
|
| 272 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 273 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 274 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 275 |
+
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
|
| 276 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 277 |
+
:param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
|
| 278 |
+
|
| 279 |
+
:returns: log directory tied to the user
|
| 280 |
+
|
| 281 |
+
"""
|
| 282 |
+
return PlatformDirs(
|
| 283 |
+
appname=appname,
|
| 284 |
+
appauthor=appauthor,
|
| 285 |
+
version=version,
|
| 286 |
+
opinion=opinion,
|
| 287 |
+
ensure_exists=ensure_exists,
|
| 288 |
+
use_site_for_root=use_site_for_root,
|
| 289 |
+
).user_log_dir
|
| 290 |
+
|
| 291 |
+
|
| 292 |
+
def site_log_dir(
|
| 293 |
+
appname: str | None = None,
|
| 294 |
+
appauthor: str | Literal[False] | None = None,
|
| 295 |
+
version: str | None = None,
|
| 296 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 297 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 298 |
+
) -> str:
|
| 299 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 300 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 301 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 302 |
+
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
|
| 303 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 304 |
+
|
| 305 |
+
:returns: log directory shared by users
|
| 306 |
+
|
| 307 |
+
"""
|
| 308 |
+
return PlatformDirs(
|
| 309 |
+
appname=appname,
|
| 310 |
+
appauthor=appauthor,
|
| 311 |
+
version=version,
|
| 312 |
+
opinion=opinion,
|
| 313 |
+
ensure_exists=ensure_exists,
|
| 314 |
+
).site_log_dir
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
def user_documents_dir() -> str:
|
| 318 |
+
""":returns: documents directory tied to the user"""
|
| 319 |
+
return PlatformDirs().user_documents_dir
|
| 320 |
+
|
| 321 |
+
|
| 322 |
+
def user_downloads_dir() -> str:
|
| 323 |
+
""":returns: downloads directory tied to the user"""
|
| 324 |
+
return PlatformDirs().user_downloads_dir
|
| 325 |
+
|
| 326 |
+
|
| 327 |
+
def user_pictures_dir() -> str:
|
| 328 |
+
""":returns: pictures directory tied to the user"""
|
| 329 |
+
return PlatformDirs().user_pictures_dir
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
def user_videos_dir() -> str:
|
| 333 |
+
""":returns: videos directory tied to the user"""
|
| 334 |
+
return PlatformDirs().user_videos_dir
|
| 335 |
+
|
| 336 |
+
|
| 337 |
+
def user_music_dir() -> str:
|
| 338 |
+
""":returns: music directory tied to the user"""
|
| 339 |
+
return PlatformDirs().user_music_dir
|
| 340 |
+
|
| 341 |
+
|
| 342 |
+
def user_desktop_dir() -> str:
|
| 343 |
+
""":returns: desktop directory tied to the user"""
|
| 344 |
+
return PlatformDirs().user_desktop_dir
|
| 345 |
+
|
| 346 |
+
|
| 347 |
+
def user_projects_dir() -> str:
|
| 348 |
+
""":returns: projects directory tied to the user"""
|
| 349 |
+
return PlatformDirs().user_projects_dir
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
def user_publicshare_dir() -> str:
|
| 353 |
+
""":returns: public share directory tied to the user"""
|
| 354 |
+
return PlatformDirs().user_publicshare_dir
|
| 355 |
+
|
| 356 |
+
|
| 357 |
+
def user_templates_dir() -> str:
|
| 358 |
+
""":returns: templates directory tied to the user"""
|
| 359 |
+
return PlatformDirs().user_templates_dir
|
| 360 |
+
|
| 361 |
+
|
| 362 |
+
def user_fonts_dir() -> str:
|
| 363 |
+
""":returns: fonts directory tied to the user"""
|
| 364 |
+
return PlatformDirs().user_fonts_dir
|
| 365 |
+
|
| 366 |
+
|
| 367 |
+
def user_preference_dir() -> str:
|
| 368 |
+
""":returns: preference directory tied to the user"""
|
| 369 |
+
return PlatformDirs().user_preference_dir
|
| 370 |
+
|
| 371 |
+
|
| 372 |
+
def user_bin_dir() -> str:
|
| 373 |
+
""":returns: bin directory tied to the user"""
|
| 374 |
+
return PlatformDirs().user_bin_dir
|
| 375 |
+
|
| 376 |
+
|
| 377 |
+
def site_bin_dir() -> str:
|
| 378 |
+
""":returns: bin directory shared by users"""
|
| 379 |
+
return PlatformDirs().site_bin_dir
|
| 380 |
+
|
| 381 |
+
|
| 382 |
+
def user_applications_dir() -> str:
|
| 383 |
+
""":returns: applications directory tied to the user"""
|
| 384 |
+
return PlatformDirs().user_applications_dir
|
| 385 |
+
|
| 386 |
+
|
| 387 |
+
def site_applications_dir(
|
| 388 |
+
multipath: bool = False, # noqa: FBT001, FBT002
|
| 389 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 390 |
+
) -> str:
|
| 391 |
+
""":param multipath: See `multipath <platformdirs.api.PlatformDirsABC.multipath>`.
|
| 392 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 393 |
+
|
| 394 |
+
:returns: applications directory shared by users
|
| 395 |
+
|
| 396 |
+
"""
|
| 397 |
+
return PlatformDirs(
|
| 398 |
+
multipath=multipath,
|
| 399 |
+
ensure_exists=ensure_exists,
|
| 400 |
+
).site_applications_dir
|
| 401 |
+
|
| 402 |
+
|
| 403 |
+
def user_runtime_dir( # noqa: PLR0913, PLR0917
|
| 404 |
+
appname: str | None = None,
|
| 405 |
+
appauthor: str | Literal[False] | None = None,
|
| 406 |
+
version: str | None = None,
|
| 407 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 408 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 409 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 410 |
+
) -> str:
|
| 411 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 412 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 413 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 414 |
+
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
|
| 415 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 416 |
+
:param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
|
| 417 |
+
|
| 418 |
+
:returns: runtime directory tied to the user
|
| 419 |
+
|
| 420 |
+
"""
|
| 421 |
+
return PlatformDirs(
|
| 422 |
+
appname=appname,
|
| 423 |
+
appauthor=appauthor,
|
| 424 |
+
version=version,
|
| 425 |
+
opinion=opinion,
|
| 426 |
+
ensure_exists=ensure_exists,
|
| 427 |
+
use_site_for_root=use_site_for_root,
|
| 428 |
+
).user_runtime_dir
|
| 429 |
+
|
| 430 |
+
|
| 431 |
+
def site_runtime_dir(
|
| 432 |
+
appname: str | None = None,
|
| 433 |
+
appauthor: str | Literal[False] | None = None,
|
| 434 |
+
version: str | None = None,
|
| 435 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 436 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 437 |
+
) -> str:
|
| 438 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 439 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 440 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 441 |
+
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
|
| 442 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 443 |
+
|
| 444 |
+
:returns: runtime directory shared by users
|
| 445 |
+
|
| 446 |
+
"""
|
| 447 |
+
return PlatformDirs(
|
| 448 |
+
appname=appname,
|
| 449 |
+
appauthor=appauthor,
|
| 450 |
+
version=version,
|
| 451 |
+
opinion=opinion,
|
| 452 |
+
ensure_exists=ensure_exists,
|
| 453 |
+
).site_runtime_dir
|
| 454 |
+
|
| 455 |
+
|
| 456 |
+
def user_data_path( # noqa: PLR0913, PLR0917
|
| 457 |
+
appname: str | None = None,
|
| 458 |
+
appauthor: str | Literal[False] | None = None,
|
| 459 |
+
version: str | None = None,
|
| 460 |
+
roaming: bool = False, # noqa: FBT001, FBT002
|
| 461 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 462 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 463 |
+
) -> Path:
|
| 464 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 465 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 466 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 467 |
+
:param roaming: See `roaming <platformdirs.api.PlatformDirsABC.roaming>`.
|
| 468 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 469 |
+
:param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
|
| 470 |
+
|
| 471 |
+
:returns: data path tied to the user
|
| 472 |
+
|
| 473 |
+
"""
|
| 474 |
+
return PlatformDirs(
|
| 475 |
+
appname=appname,
|
| 476 |
+
appauthor=appauthor,
|
| 477 |
+
version=version,
|
| 478 |
+
roaming=roaming,
|
| 479 |
+
ensure_exists=ensure_exists,
|
| 480 |
+
use_site_for_root=use_site_for_root,
|
| 481 |
+
).user_data_path
|
| 482 |
+
|
| 483 |
+
|
| 484 |
+
def site_data_path(
|
| 485 |
+
appname: str | None = None,
|
| 486 |
+
appauthor: str | Literal[False] | None = None,
|
| 487 |
+
version: str | None = None,
|
| 488 |
+
multipath: bool = False, # noqa: FBT001, FBT002
|
| 489 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 490 |
+
) -> Path:
|
| 491 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 492 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 493 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 494 |
+
:param multipath: See `multipath <platformdirs.api.PlatformDirsABC.multipath>`.
|
| 495 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 496 |
+
|
| 497 |
+
:returns: data path shared by users
|
| 498 |
+
|
| 499 |
+
"""
|
| 500 |
+
return PlatformDirs(
|
| 501 |
+
appname=appname,
|
| 502 |
+
appauthor=appauthor,
|
| 503 |
+
version=version,
|
| 504 |
+
multipath=multipath,
|
| 505 |
+
ensure_exists=ensure_exists,
|
| 506 |
+
).site_data_path
|
| 507 |
+
|
| 508 |
+
|
| 509 |
+
def user_config_path( # noqa: PLR0913, PLR0917
|
| 510 |
+
appname: str | None = None,
|
| 511 |
+
appauthor: str | Literal[False] | None = None,
|
| 512 |
+
version: str | None = None,
|
| 513 |
+
roaming: bool = False, # noqa: FBT001, FBT002
|
| 514 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 515 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 516 |
+
) -> Path:
|
| 517 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 518 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 519 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 520 |
+
:param roaming: See `roaming <platformdirs.api.PlatformDirsABC.roaming>`.
|
| 521 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 522 |
+
:param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
|
| 523 |
+
|
| 524 |
+
:returns: config path tied to the user
|
| 525 |
+
|
| 526 |
+
"""
|
| 527 |
+
return PlatformDirs(
|
| 528 |
+
appname=appname,
|
| 529 |
+
appauthor=appauthor,
|
| 530 |
+
version=version,
|
| 531 |
+
roaming=roaming,
|
| 532 |
+
ensure_exists=ensure_exists,
|
| 533 |
+
use_site_for_root=use_site_for_root,
|
| 534 |
+
).user_config_path
|
| 535 |
+
|
| 536 |
+
|
| 537 |
+
def site_config_path(
|
| 538 |
+
appname: str | None = None,
|
| 539 |
+
appauthor: str | Literal[False] | None = None,
|
| 540 |
+
version: str | None = None,
|
| 541 |
+
multipath: bool = False, # noqa: FBT001, FBT002
|
| 542 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 543 |
+
) -> Path:
|
| 544 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 545 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 546 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 547 |
+
:param multipath: See `multipath <platformdirs.api.PlatformDirsABC.multipath>`.
|
| 548 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 549 |
+
|
| 550 |
+
:returns: config path shared by users
|
| 551 |
+
|
| 552 |
+
"""
|
| 553 |
+
return PlatformDirs(
|
| 554 |
+
appname=appname,
|
| 555 |
+
appauthor=appauthor,
|
| 556 |
+
version=version,
|
| 557 |
+
multipath=multipath,
|
| 558 |
+
ensure_exists=ensure_exists,
|
| 559 |
+
).site_config_path
|
| 560 |
+
|
| 561 |
+
|
| 562 |
+
def site_cache_path(
|
| 563 |
+
appname: str | None = None,
|
| 564 |
+
appauthor: str | Literal[False] | None = None,
|
| 565 |
+
version: str | None = None,
|
| 566 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 567 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 568 |
+
) -> Path:
|
| 569 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 570 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 571 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 572 |
+
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
|
| 573 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 574 |
+
|
| 575 |
+
:returns: cache path shared by users
|
| 576 |
+
|
| 577 |
+
"""
|
| 578 |
+
return PlatformDirs(
|
| 579 |
+
appname=appname,
|
| 580 |
+
appauthor=appauthor,
|
| 581 |
+
version=version,
|
| 582 |
+
opinion=opinion,
|
| 583 |
+
ensure_exists=ensure_exists,
|
| 584 |
+
).site_cache_path
|
| 585 |
+
|
| 586 |
+
|
| 587 |
+
def user_cache_path( # noqa: PLR0913, PLR0917
|
| 588 |
+
appname: str | None = None,
|
| 589 |
+
appauthor: str | Literal[False] | None = None,
|
| 590 |
+
version: str | None = None,
|
| 591 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 592 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 593 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 594 |
+
) -> Path:
|
| 595 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 596 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 597 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 598 |
+
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
|
| 599 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 600 |
+
:param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
|
| 601 |
+
|
| 602 |
+
:returns: cache path tied to the user
|
| 603 |
+
|
| 604 |
+
"""
|
| 605 |
+
return PlatformDirs(
|
| 606 |
+
appname=appname,
|
| 607 |
+
appauthor=appauthor,
|
| 608 |
+
version=version,
|
| 609 |
+
opinion=opinion,
|
| 610 |
+
ensure_exists=ensure_exists,
|
| 611 |
+
use_site_for_root=use_site_for_root,
|
| 612 |
+
).user_cache_path
|
| 613 |
+
|
| 614 |
+
|
| 615 |
+
def user_state_path( # noqa: PLR0913, PLR0917
|
| 616 |
+
appname: str | None = None,
|
| 617 |
+
appauthor: str | Literal[False] | None = None,
|
| 618 |
+
version: str | None = None,
|
| 619 |
+
roaming: bool = False, # noqa: FBT001, FBT002
|
| 620 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 621 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 622 |
+
) -> Path:
|
| 623 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 624 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 625 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 626 |
+
:param roaming: See `roaming <platformdirs.api.PlatformDirsABC.roaming>`.
|
| 627 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 628 |
+
:param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
|
| 629 |
+
|
| 630 |
+
:returns: state path tied to the user
|
| 631 |
+
|
| 632 |
+
"""
|
| 633 |
+
return PlatformDirs(
|
| 634 |
+
appname=appname,
|
| 635 |
+
appauthor=appauthor,
|
| 636 |
+
version=version,
|
| 637 |
+
roaming=roaming,
|
| 638 |
+
ensure_exists=ensure_exists,
|
| 639 |
+
use_site_for_root=use_site_for_root,
|
| 640 |
+
).user_state_path
|
| 641 |
+
|
| 642 |
+
|
| 643 |
+
def site_state_path(
|
| 644 |
+
appname: str | None = None,
|
| 645 |
+
appauthor: str | Literal[False] | None = None,
|
| 646 |
+
version: str | None = None,
|
| 647 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 648 |
+
) -> Path:
|
| 649 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 650 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 651 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 652 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 653 |
+
|
| 654 |
+
:returns: state path shared by users
|
| 655 |
+
|
| 656 |
+
"""
|
| 657 |
+
return PlatformDirs(
|
| 658 |
+
appname=appname,
|
| 659 |
+
appauthor=appauthor,
|
| 660 |
+
version=version,
|
| 661 |
+
ensure_exists=ensure_exists,
|
| 662 |
+
).site_state_path
|
| 663 |
+
|
| 664 |
+
|
| 665 |
+
def user_log_path( # noqa: PLR0913, PLR0917
|
| 666 |
+
appname: str | None = None,
|
| 667 |
+
appauthor: str | Literal[False] | None = None,
|
| 668 |
+
version: str | None = None,
|
| 669 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 670 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 671 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 672 |
+
) -> Path:
|
| 673 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 674 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 675 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 676 |
+
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
|
| 677 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 678 |
+
:param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
|
| 679 |
+
|
| 680 |
+
:returns: log path tied to the user
|
| 681 |
+
|
| 682 |
+
"""
|
| 683 |
+
return PlatformDirs(
|
| 684 |
+
appname=appname,
|
| 685 |
+
appauthor=appauthor,
|
| 686 |
+
version=version,
|
| 687 |
+
opinion=opinion,
|
| 688 |
+
ensure_exists=ensure_exists,
|
| 689 |
+
use_site_for_root=use_site_for_root,
|
| 690 |
+
).user_log_path
|
| 691 |
+
|
| 692 |
+
|
| 693 |
+
def site_log_path(
|
| 694 |
+
appname: str | None = None,
|
| 695 |
+
appauthor: str | Literal[False] | None = None,
|
| 696 |
+
version: str | None = None,
|
| 697 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 698 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 699 |
+
) -> Path:
|
| 700 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 701 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 702 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 703 |
+
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
|
| 704 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 705 |
+
|
| 706 |
+
:returns: log path shared by users
|
| 707 |
+
|
| 708 |
+
"""
|
| 709 |
+
return PlatformDirs(
|
| 710 |
+
appname=appname,
|
| 711 |
+
appauthor=appauthor,
|
| 712 |
+
version=version,
|
| 713 |
+
opinion=opinion,
|
| 714 |
+
ensure_exists=ensure_exists,
|
| 715 |
+
).site_log_path
|
| 716 |
+
|
| 717 |
+
|
| 718 |
+
def user_documents_path() -> Path:
|
| 719 |
+
""":returns: documents path tied to the user"""
|
| 720 |
+
return PlatformDirs().user_documents_path
|
| 721 |
+
|
| 722 |
+
|
| 723 |
+
def user_downloads_path() -> Path:
|
| 724 |
+
""":returns: downloads path tied to the user"""
|
| 725 |
+
return PlatformDirs().user_downloads_path
|
| 726 |
+
|
| 727 |
+
|
| 728 |
+
def user_pictures_path() -> Path:
|
| 729 |
+
""":returns: pictures path tied to the user"""
|
| 730 |
+
return PlatformDirs().user_pictures_path
|
| 731 |
+
|
| 732 |
+
|
| 733 |
+
def user_videos_path() -> Path:
|
| 734 |
+
""":returns: videos path tied to the user"""
|
| 735 |
+
return PlatformDirs().user_videos_path
|
| 736 |
+
|
| 737 |
+
|
| 738 |
+
def user_music_path() -> Path:
|
| 739 |
+
""":returns: music path tied to the user"""
|
| 740 |
+
return PlatformDirs().user_music_path
|
| 741 |
+
|
| 742 |
+
|
| 743 |
+
def user_desktop_path() -> Path:
|
| 744 |
+
""":returns: desktop path tied to the user"""
|
| 745 |
+
return PlatformDirs().user_desktop_path
|
| 746 |
+
|
| 747 |
+
|
| 748 |
+
def user_projects_path() -> Path:
|
| 749 |
+
""":returns: projects path tied to the user"""
|
| 750 |
+
return PlatformDirs().user_projects_path
|
| 751 |
+
|
| 752 |
+
|
| 753 |
+
def user_publicshare_path() -> Path:
|
| 754 |
+
""":returns: public share path tied to the user"""
|
| 755 |
+
return PlatformDirs().user_publicshare_path
|
| 756 |
+
|
| 757 |
+
|
| 758 |
+
def user_templates_path() -> Path:
|
| 759 |
+
""":returns: templates path tied to the user"""
|
| 760 |
+
return PlatformDirs().user_templates_path
|
| 761 |
+
|
| 762 |
+
|
| 763 |
+
def user_fonts_path() -> Path:
|
| 764 |
+
""":returns: fonts path tied to the user"""
|
| 765 |
+
return PlatformDirs().user_fonts_path
|
| 766 |
+
|
| 767 |
+
|
| 768 |
+
def user_preference_path() -> Path:
|
| 769 |
+
""":returns: preference path tied to the user"""
|
| 770 |
+
return PlatformDirs().user_preference_path
|
| 771 |
+
|
| 772 |
+
|
| 773 |
+
def user_bin_path() -> Path:
|
| 774 |
+
""":returns: bin path tied to the user"""
|
| 775 |
+
return PlatformDirs().user_bin_path
|
| 776 |
+
|
| 777 |
+
|
| 778 |
+
def site_bin_path() -> Path:
|
| 779 |
+
""":returns: bin path shared by users"""
|
| 780 |
+
return PlatformDirs().site_bin_path
|
| 781 |
+
|
| 782 |
+
|
| 783 |
+
def user_applications_path() -> Path:
|
| 784 |
+
""":returns: applications path tied to the user"""
|
| 785 |
+
return PlatformDirs().user_applications_path
|
| 786 |
+
|
| 787 |
+
|
| 788 |
+
def site_applications_path(
|
| 789 |
+
multipath: bool = False, # noqa: FBT001, FBT002
|
| 790 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 791 |
+
) -> Path:
|
| 792 |
+
""":param multipath: See `multipath <platformdirs.api.PlatformDirsABC.multipath>`.
|
| 793 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 794 |
+
|
| 795 |
+
:returns: applications path shared by users
|
| 796 |
+
|
| 797 |
+
"""
|
| 798 |
+
return PlatformDirs(
|
| 799 |
+
multipath=multipath,
|
| 800 |
+
ensure_exists=ensure_exists,
|
| 801 |
+
).site_applications_path
|
| 802 |
+
|
| 803 |
+
|
| 804 |
+
def user_runtime_path( # noqa: PLR0913, PLR0917
|
| 805 |
+
appname: str | None = None,
|
| 806 |
+
appauthor: str | Literal[False] | None = None,
|
| 807 |
+
version: str | None = None,
|
| 808 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 809 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 810 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 811 |
+
) -> Path:
|
| 812 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 813 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 814 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 815 |
+
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
|
| 816 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 817 |
+
:param use_site_for_root: See `use_site_for_root <platformdirs.api.PlatformDirsABC.use_site_for_root>`.
|
| 818 |
+
|
| 819 |
+
:returns: runtime path tied to the user
|
| 820 |
+
|
| 821 |
+
"""
|
| 822 |
+
return PlatformDirs(
|
| 823 |
+
appname=appname,
|
| 824 |
+
appauthor=appauthor,
|
| 825 |
+
version=version,
|
| 826 |
+
opinion=opinion,
|
| 827 |
+
ensure_exists=ensure_exists,
|
| 828 |
+
use_site_for_root=use_site_for_root,
|
| 829 |
+
).user_runtime_path
|
| 830 |
+
|
| 831 |
+
|
| 832 |
+
def site_runtime_path(
|
| 833 |
+
appname: str | None = None,
|
| 834 |
+
appauthor: str | Literal[False] | None = None,
|
| 835 |
+
version: str | None = None,
|
| 836 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 837 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 838 |
+
) -> Path:
|
| 839 |
+
""":param appname: See `appname <platformdirs.api.PlatformDirsABC.appname>`.
|
| 840 |
+
:param appauthor: See `appauthor <platformdirs.api.PlatformDirsABC.appauthor>`.
|
| 841 |
+
:param version: See `version <platformdirs.api.PlatformDirsABC.version>`.
|
| 842 |
+
:param opinion: See `opinion <platformdirs.api.PlatformDirsABC.opinion>`.
|
| 843 |
+
:param ensure_exists: See `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 844 |
+
|
| 845 |
+
:returns: runtime path shared by users
|
| 846 |
+
|
| 847 |
+
"""
|
| 848 |
+
return PlatformDirs(
|
| 849 |
+
appname=appname,
|
| 850 |
+
appauthor=appauthor,
|
| 851 |
+
version=version,
|
| 852 |
+
opinion=opinion,
|
| 853 |
+
ensure_exists=ensure_exists,
|
| 854 |
+
).site_runtime_path
|
| 855 |
+
|
| 856 |
+
|
| 857 |
+
__all__ = [
|
| 858 |
+
"AppDirs",
|
| 859 |
+
"PlatformDirs",
|
| 860 |
+
"PlatformDirsABC",
|
| 861 |
+
"__version__",
|
| 862 |
+
"__version_info__",
|
| 863 |
+
"site_applications_dir",
|
| 864 |
+
"site_applications_path",
|
| 865 |
+
"site_bin_dir",
|
| 866 |
+
"site_bin_path",
|
| 867 |
+
"site_cache_dir",
|
| 868 |
+
"site_cache_path",
|
| 869 |
+
"site_config_dir",
|
| 870 |
+
"site_config_path",
|
| 871 |
+
"site_data_dir",
|
| 872 |
+
"site_data_path",
|
| 873 |
+
"site_log_dir",
|
| 874 |
+
"site_log_path",
|
| 875 |
+
"site_runtime_dir",
|
| 876 |
+
"site_runtime_path",
|
| 877 |
+
"site_state_dir",
|
| 878 |
+
"site_state_path",
|
| 879 |
+
"user_applications_dir",
|
| 880 |
+
"user_applications_path",
|
| 881 |
+
"user_bin_dir",
|
| 882 |
+
"user_bin_path",
|
| 883 |
+
"user_cache_dir",
|
| 884 |
+
"user_cache_path",
|
| 885 |
+
"user_config_dir",
|
| 886 |
+
"user_config_path",
|
| 887 |
+
"user_data_dir",
|
| 888 |
+
"user_data_path",
|
| 889 |
+
"user_desktop_dir",
|
| 890 |
+
"user_desktop_path",
|
| 891 |
+
"user_documents_dir",
|
| 892 |
+
"user_documents_path",
|
| 893 |
+
"user_downloads_dir",
|
| 894 |
+
"user_downloads_path",
|
| 895 |
+
"user_fonts_dir",
|
| 896 |
+
"user_fonts_path",
|
| 897 |
+
"user_log_dir",
|
| 898 |
+
"user_log_path",
|
| 899 |
+
"user_music_dir",
|
| 900 |
+
"user_music_path",
|
| 901 |
+
"user_pictures_dir",
|
| 902 |
+
"user_pictures_path",
|
| 903 |
+
"user_preference_dir",
|
| 904 |
+
"user_preference_path",
|
| 905 |
+
"user_projects_dir",
|
| 906 |
+
"user_projects_path",
|
| 907 |
+
"user_publicshare_dir",
|
| 908 |
+
"user_publicshare_path",
|
| 909 |
+
"user_runtime_dir",
|
| 910 |
+
"user_runtime_path",
|
| 911 |
+
"user_state_dir",
|
| 912 |
+
"user_state_path",
|
| 913 |
+
"user_templates_dir",
|
| 914 |
+
"user_templates_path",
|
| 915 |
+
"user_videos_dir",
|
| 916 |
+
"user_videos_path",
|
| 917 |
+
]
|
.venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/__main__.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Main entry point."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
from pip._vendor.platformdirs import PlatformDirs, __version__
|
| 6 |
+
|
| 7 |
+
PROPS = (
|
| 8 |
+
"user_data_dir",
|
| 9 |
+
"user_config_dir",
|
| 10 |
+
"user_cache_dir",
|
| 11 |
+
"user_state_dir",
|
| 12 |
+
"user_log_dir",
|
| 13 |
+
"user_documents_dir",
|
| 14 |
+
"user_downloads_dir",
|
| 15 |
+
"user_pictures_dir",
|
| 16 |
+
"user_videos_dir",
|
| 17 |
+
"user_music_dir",
|
| 18 |
+
"user_projects_dir",
|
| 19 |
+
"user_publicshare_dir",
|
| 20 |
+
"user_templates_dir",
|
| 21 |
+
"user_fonts_dir",
|
| 22 |
+
"user_preference_dir",
|
| 23 |
+
"user_bin_dir",
|
| 24 |
+
"site_bin_dir",
|
| 25 |
+
"user_applications_dir",
|
| 26 |
+
"user_runtime_dir",
|
| 27 |
+
"site_data_dir",
|
| 28 |
+
"site_config_dir",
|
| 29 |
+
"site_cache_dir",
|
| 30 |
+
"site_state_dir",
|
| 31 |
+
"site_log_dir",
|
| 32 |
+
"site_applications_dir",
|
| 33 |
+
"site_runtime_dir",
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def main() -> None:
|
| 38 |
+
"""Run the main entry point."""
|
| 39 |
+
app_name = "MyApp"
|
| 40 |
+
app_author = "MyCompany"
|
| 41 |
+
|
| 42 |
+
print(f"-- platformdirs {__version__} --") # noqa: T201
|
| 43 |
+
|
| 44 |
+
print("-- app dirs (with optional 'version')") # noqa: T201
|
| 45 |
+
dirs = PlatformDirs(app_name, app_author, version="1.0")
|
| 46 |
+
for prop in PROPS:
|
| 47 |
+
print(f"{prop}: {getattr(dirs, prop)}") # noqa: T201
|
| 48 |
+
|
| 49 |
+
print("\n-- app dirs (without optional 'version')") # noqa: T201
|
| 50 |
+
dirs = PlatformDirs(app_name, app_author)
|
| 51 |
+
for prop in PROPS:
|
| 52 |
+
print(f"{prop}: {getattr(dirs, prop)}") # noqa: T201
|
| 53 |
+
|
| 54 |
+
print("\n-- app dirs (without optional 'appauthor')") # noqa: T201
|
| 55 |
+
dirs = PlatformDirs(app_name)
|
| 56 |
+
for prop in PROPS:
|
| 57 |
+
print(f"{prop}: {getattr(dirs, prop)}") # noqa: T201
|
| 58 |
+
|
| 59 |
+
print("\n-- app dirs (with disabled 'appauthor')") # noqa: T201
|
| 60 |
+
dirs = PlatformDirs(app_name, appauthor=False)
|
| 61 |
+
for prop in PROPS:
|
| 62 |
+
print(f"{prop}: {getattr(dirs, prop)}") # noqa: T201
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
if __name__ == "__main__":
|
| 66 |
+
main()
|
.venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/_xdg.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""XDG environment variable mixin for Unix and macOS."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
from .api import PlatformDirsABC
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class XDGMixin(PlatformDirsABC):
|
| 11 |
+
"""Mixin that checks XDG environment variables, falling back to platform-specific defaults via ``super()``."""
|
| 12 |
+
|
| 13 |
+
@property
|
| 14 |
+
def user_data_dir(self) -> str:
|
| 15 |
+
""":returns: data directory tied to the user, from ``$XDG_DATA_HOME`` if set, else platform default"""
|
| 16 |
+
if path := os.environ.get("XDG_DATA_HOME", "").strip():
|
| 17 |
+
return self._append_app_name_and_version(path)
|
| 18 |
+
return super().user_data_dir
|
| 19 |
+
|
| 20 |
+
@property
|
| 21 |
+
def _site_data_dirs(self) -> list[str]:
|
| 22 |
+
if xdg_dirs := os.environ.get("XDG_DATA_DIRS", "").strip():
|
| 23 |
+
return [self._append_app_name_and_version(p) for p in xdg_dirs.split(os.pathsep) if p.strip()]
|
| 24 |
+
return super()._site_data_dirs
|
| 25 |
+
|
| 26 |
+
@property
|
| 27 |
+
def site_data_dir(self) -> str:
|
| 28 |
+
""":returns: data directories shared by users, from ``$XDG_DATA_DIRS`` if set, else platform default"""
|
| 29 |
+
dirs = self._site_data_dirs
|
| 30 |
+
return os.pathsep.join(dirs) if self.multipath else dirs[0]
|
| 31 |
+
|
| 32 |
+
@property
|
| 33 |
+
def user_config_dir(self) -> str:
|
| 34 |
+
""":returns: config directory tied to the user, from ``$XDG_CONFIG_HOME`` if set, else platform default"""
|
| 35 |
+
if path := os.environ.get("XDG_CONFIG_HOME", "").strip():
|
| 36 |
+
return self._append_app_name_and_version(path)
|
| 37 |
+
return super().user_config_dir
|
| 38 |
+
|
| 39 |
+
@property
|
| 40 |
+
def _site_config_dirs(self) -> list[str]:
|
| 41 |
+
if xdg_dirs := os.environ.get("XDG_CONFIG_DIRS", "").strip():
|
| 42 |
+
return [self._append_app_name_and_version(p) for p in xdg_dirs.split(os.pathsep) if p.strip()]
|
| 43 |
+
return super()._site_config_dirs
|
| 44 |
+
|
| 45 |
+
@property
|
| 46 |
+
def site_config_dir(self) -> str:
|
| 47 |
+
""":returns: config directories shared by users, from ``$XDG_CONFIG_DIRS`` if set, else platform default"""
|
| 48 |
+
dirs = self._site_config_dirs
|
| 49 |
+
return os.pathsep.join(dirs) if self.multipath else dirs[0]
|
| 50 |
+
|
| 51 |
+
@property
|
| 52 |
+
def user_cache_dir(self) -> str:
|
| 53 |
+
""":returns: cache directory tied to the user, from ``$XDG_CACHE_HOME`` if set, else platform default"""
|
| 54 |
+
if path := os.environ.get("XDG_CACHE_HOME", "").strip():
|
| 55 |
+
return self._append_app_name_and_version(path)
|
| 56 |
+
return super().user_cache_dir
|
| 57 |
+
|
| 58 |
+
@property
|
| 59 |
+
def user_state_dir(self) -> str:
|
| 60 |
+
""":returns: state directory tied to the user, from ``$XDG_STATE_HOME`` if set, else platform default"""
|
| 61 |
+
if path := os.environ.get("XDG_STATE_HOME", "").strip():
|
| 62 |
+
return self._append_app_name_and_version(path)
|
| 63 |
+
return super().user_state_dir
|
| 64 |
+
|
| 65 |
+
@property
|
| 66 |
+
def user_runtime_dir(self) -> str:
|
| 67 |
+
""":returns: runtime directory tied to the user, from ``$XDG_RUNTIME_DIR`` if set, else platform default"""
|
| 68 |
+
if path := os.environ.get("XDG_RUNTIME_DIR", "").strip():
|
| 69 |
+
return self._append_app_name_and_version(path)
|
| 70 |
+
return super().user_runtime_dir
|
| 71 |
+
|
| 72 |
+
@property
|
| 73 |
+
def site_runtime_dir(self) -> str:
|
| 74 |
+
""":returns: runtime directory shared by users, from ``$XDG_RUNTIME_DIR`` if set, else platform default"""
|
| 75 |
+
if path := os.environ.get("XDG_RUNTIME_DIR", "").strip():
|
| 76 |
+
return self._append_app_name_and_version(path)
|
| 77 |
+
return super().site_runtime_dir
|
| 78 |
+
|
| 79 |
+
@property
|
| 80 |
+
def user_documents_dir(self) -> str:
|
| 81 |
+
""":returns: documents directory tied to the user, from ``$XDG_DOCUMENTS_DIR`` if set, else platform default"""
|
| 82 |
+
if path := os.environ.get("XDG_DOCUMENTS_DIR", "").strip():
|
| 83 |
+
return os.path.expanduser(path) # noqa: PTH111
|
| 84 |
+
return super().user_documents_dir
|
| 85 |
+
|
| 86 |
+
@property
|
| 87 |
+
def user_downloads_dir(self) -> str:
|
| 88 |
+
""":returns: downloads directory tied to the user, from ``$XDG_DOWNLOAD_DIR`` if set, else platform default"""
|
| 89 |
+
if path := os.environ.get("XDG_DOWNLOAD_DIR", "").strip():
|
| 90 |
+
return os.path.expanduser(path) # noqa: PTH111
|
| 91 |
+
return super().user_downloads_dir
|
| 92 |
+
|
| 93 |
+
@property
|
| 94 |
+
def user_pictures_dir(self) -> str:
|
| 95 |
+
""":returns: pictures directory tied to the user, from ``$XDG_PICTURES_DIR`` if set, else platform default"""
|
| 96 |
+
if path := os.environ.get("XDG_PICTURES_DIR", "").strip():
|
| 97 |
+
return os.path.expanduser(path) # noqa: PTH111
|
| 98 |
+
return super().user_pictures_dir
|
| 99 |
+
|
| 100 |
+
@property
|
| 101 |
+
def user_videos_dir(self) -> str:
|
| 102 |
+
""":returns: videos directory tied to the user, from ``$XDG_VIDEOS_DIR`` if set, else platform default"""
|
| 103 |
+
if path := os.environ.get("XDG_VIDEOS_DIR", "").strip():
|
| 104 |
+
return os.path.expanduser(path) # noqa: PTH111
|
| 105 |
+
return super().user_videos_dir
|
| 106 |
+
|
| 107 |
+
@property
|
| 108 |
+
def user_music_dir(self) -> str:
|
| 109 |
+
""":returns: music directory tied to the user, from ``$XDG_MUSIC_DIR`` if set, else platform default"""
|
| 110 |
+
if path := os.environ.get("XDG_MUSIC_DIR", "").strip():
|
| 111 |
+
return os.path.expanduser(path) # noqa: PTH111
|
| 112 |
+
return super().user_music_dir
|
| 113 |
+
|
| 114 |
+
@property
|
| 115 |
+
def user_desktop_dir(self) -> str:
|
| 116 |
+
""":returns: desktop directory tied to the user, from ``$XDG_DESKTOP_DIR`` if set, else platform default"""
|
| 117 |
+
if path := os.environ.get("XDG_DESKTOP_DIR", "").strip():
|
| 118 |
+
return os.path.expanduser(path) # noqa: PTH111
|
| 119 |
+
return super().user_desktop_dir
|
| 120 |
+
|
| 121 |
+
@property
|
| 122 |
+
def user_projects_dir(self) -> str:
|
| 123 |
+
""":returns: projects directory tied to the user, from ``$XDG_PROJECTS_DIR`` if set, else platform default"""
|
| 124 |
+
if path := os.environ.get("XDG_PROJECTS_DIR", "").strip():
|
| 125 |
+
return os.path.expanduser(path) # noqa: PTH111 # API returns str, not Path
|
| 126 |
+
return super().user_projects_dir
|
| 127 |
+
|
| 128 |
+
@property
|
| 129 |
+
def user_publicshare_dir(self) -> str:
|
| 130 |
+
""":returns: public share directory tied to the user, from ``$XDG_PUBLICSHARE_DIR`` if set, else platform default"""
|
| 131 |
+
if path := os.environ.get("XDG_PUBLICSHARE_DIR", "").strip():
|
| 132 |
+
return os.path.expanduser(path) # noqa: PTH111 # API returns str, not Path
|
| 133 |
+
return super().user_publicshare_dir
|
| 134 |
+
|
| 135 |
+
@property
|
| 136 |
+
def user_templates_dir(self) -> str:
|
| 137 |
+
""":returns: templates directory tied to the user, from ``$XDG_TEMPLATES_DIR`` if set, else platform default"""
|
| 138 |
+
if path := os.environ.get("XDG_TEMPLATES_DIR", "").strip():
|
| 139 |
+
return os.path.expanduser(path) # noqa: PTH111 # API returns str, not Path
|
| 140 |
+
return super().user_templates_dir
|
| 141 |
+
|
| 142 |
+
@property
|
| 143 |
+
def user_fonts_dir(self) -> str:
|
| 144 |
+
""":returns: fonts directory tied to the user, from ``$XDG_DATA_HOME/fonts`` if set, else platform default"""
|
| 145 |
+
if path := os.environ.get("XDG_DATA_HOME", "").strip():
|
| 146 |
+
return f"{os.path.expanduser(path)}/fonts" # noqa: PTH111 # API returns str, not Path
|
| 147 |
+
return super().user_fonts_dir
|
| 148 |
+
|
| 149 |
+
@property
|
| 150 |
+
def user_applications_dir(self) -> str:
|
| 151 |
+
""":returns: applications directory tied to the user, from ``$XDG_DATA_HOME`` if set, else platform default"""
|
| 152 |
+
if path := os.environ.get("XDG_DATA_HOME", "").strip():
|
| 153 |
+
return os.path.join(os.path.expanduser(path), "applications") # noqa: PTH111, PTH118
|
| 154 |
+
return super().user_applications_dir
|
| 155 |
+
|
| 156 |
+
@property
|
| 157 |
+
def _site_applications_dirs(self) -> list[str]:
|
| 158 |
+
if xdg_dirs := os.environ.get("XDG_DATA_DIRS", "").strip():
|
| 159 |
+
return [os.path.join(p, "applications") for p in xdg_dirs.split(os.pathsep) if p.strip()] # noqa: PTH118
|
| 160 |
+
return super()._site_applications_dirs
|
| 161 |
+
|
| 162 |
+
@property
|
| 163 |
+
def site_applications_dir(self) -> str:
|
| 164 |
+
""":returns: applications directories shared by users, from ``$XDG_DATA_DIRS`` if set, else platform default"""
|
| 165 |
+
dirs = self._site_applications_dirs
|
| 166 |
+
return os.pathsep.join(dirs) if self.multipath else dirs[0]
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
__all__ = [
|
| 170 |
+
"XDGMixin",
|
| 171 |
+
]
|
.venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/android.py
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Android."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
import re
|
| 7 |
+
import sys
|
| 8 |
+
from functools import lru_cache
|
| 9 |
+
from typing import TYPE_CHECKING, cast
|
| 10 |
+
|
| 11 |
+
from .api import PlatformDirsABC
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
class Android(PlatformDirsABC): # noqa: PLR0904
|
| 15 |
+
"""Platform directories for Android.
|
| 16 |
+
|
| 17 |
+
Follows the guidance `from here <https://android.stackexchange.com/a/216132>`_. Directories are typically located
|
| 18 |
+
under the app's private storage (``/data/user/<userid>/<packagename>/``).
|
| 19 |
+
|
| 20 |
+
Makes use of the `appname <platformdirs.api.PlatformDirsABC.appname>`, `version
|
| 21 |
+
<platformdirs.api.PlatformDirsABC.version>`, `opinion <platformdirs.api.PlatformDirsABC.opinion>`, `ensure_exists
|
| 22 |
+
<platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 23 |
+
|
| 24 |
+
"""
|
| 25 |
+
|
| 26 |
+
@property
|
| 27 |
+
def user_data_dir(self) -> str:
|
| 28 |
+
""":returns: data directory tied to the user, e.g. ``/data/user/<userid>/<packagename>/files/<AppName>``"""
|
| 29 |
+
return self._append_app_name_and_version(cast("str", _android_folder()), "files")
|
| 30 |
+
|
| 31 |
+
@property
|
| 32 |
+
def site_data_dir(self) -> str:
|
| 33 |
+
""":returns: data directory shared by users, same as `user_data_dir`"""
|
| 34 |
+
return self.user_data_dir
|
| 35 |
+
|
| 36 |
+
@property
|
| 37 |
+
def user_config_dir(self) -> str:
|
| 38 |
+
""":returns: config directory tied to the user, e.g. ``/data/user/<userid>/<packagename>/shared_prefs/<AppName>``"""
|
| 39 |
+
return self._append_app_name_and_version(cast("str", _android_folder()), "shared_prefs")
|
| 40 |
+
|
| 41 |
+
@property
|
| 42 |
+
def site_config_dir(self) -> str:
|
| 43 |
+
""":returns: config directory shared by users, same as `user_config_dir`"""
|
| 44 |
+
return self.user_config_dir
|
| 45 |
+
|
| 46 |
+
@property
|
| 47 |
+
def user_cache_dir(self) -> str:
|
| 48 |
+
""":returns: cache directory tied to the user, e.g.,``/data/user/<userid>/<packagename>/cache/<AppName>``"""
|
| 49 |
+
return self._append_app_name_and_version(cast("str", _android_folder()), "cache")
|
| 50 |
+
|
| 51 |
+
@property
|
| 52 |
+
def site_cache_dir(self) -> str:
|
| 53 |
+
""":returns: cache directory shared by users, same as `user_cache_dir`"""
|
| 54 |
+
return self.user_cache_dir
|
| 55 |
+
|
| 56 |
+
@property
|
| 57 |
+
def user_state_dir(self) -> str:
|
| 58 |
+
""":returns: state directory tied to the user, same as `user_data_dir`"""
|
| 59 |
+
return self.user_data_dir
|
| 60 |
+
|
| 61 |
+
@property
|
| 62 |
+
def site_state_dir(self) -> str:
|
| 63 |
+
""":returns: state directory shared by users, same as `user_state_dir`"""
|
| 64 |
+
return self.user_state_dir
|
| 65 |
+
|
| 66 |
+
@property
|
| 67 |
+
def user_log_dir(self) -> str:
|
| 68 |
+
""":returns: log directory tied to the user, same as `user_cache_dir` if not opinionated else ``log`` in it, e.g. ``/data/user/<userid>/<packagename>/cache/<AppName>/log``"""
|
| 69 |
+
path = self.user_cache_dir
|
| 70 |
+
if self.opinion:
|
| 71 |
+
path = os.path.join(path, "log") # noqa: PTH118
|
| 72 |
+
self._optionally_create_directory(path)
|
| 73 |
+
return path
|
| 74 |
+
|
| 75 |
+
@property
|
| 76 |
+
def site_log_dir(self) -> str:
|
| 77 |
+
""":returns: log directory shared by users, same as `user_log_dir`"""
|
| 78 |
+
return self.user_log_dir
|
| 79 |
+
|
| 80 |
+
@property
|
| 81 |
+
def user_documents_dir(self) -> str:
|
| 82 |
+
""":returns: documents directory tied to the user e.g. ``/storage/emulated/0/Documents``"""
|
| 83 |
+
return _android_documents_folder()
|
| 84 |
+
|
| 85 |
+
@property
|
| 86 |
+
def user_downloads_dir(self) -> str:
|
| 87 |
+
""":returns: downloads directory tied to the user e.g. ``/storage/emulated/0/Downloads``"""
|
| 88 |
+
return _android_downloads_folder()
|
| 89 |
+
|
| 90 |
+
@property
|
| 91 |
+
def user_pictures_dir(self) -> str:
|
| 92 |
+
""":returns: pictures directory tied to the user e.g. ``/storage/emulated/0/Pictures``"""
|
| 93 |
+
return _android_pictures_folder()
|
| 94 |
+
|
| 95 |
+
@property
|
| 96 |
+
def user_videos_dir(self) -> str:
|
| 97 |
+
""":returns: videos directory tied to the user e.g. ``/storage/emulated/0/DCIM/Camera``"""
|
| 98 |
+
return _android_videos_folder()
|
| 99 |
+
|
| 100 |
+
@property
|
| 101 |
+
def user_music_dir(self) -> str:
|
| 102 |
+
""":returns: music directory tied to the user e.g. ``/storage/emulated/0/Music``"""
|
| 103 |
+
return _android_music_folder()
|
| 104 |
+
|
| 105 |
+
@property
|
| 106 |
+
def user_desktop_dir(self) -> str:
|
| 107 |
+
""":returns: desktop directory tied to the user e.g. ``/storage/emulated/0/Desktop``"""
|
| 108 |
+
return "/storage/emulated/0/Desktop"
|
| 109 |
+
|
| 110 |
+
@property
|
| 111 |
+
def user_projects_dir(self) -> str:
|
| 112 |
+
""":returns: projects directory tied to the user e.g. ``/storage/emulated/0/Projects``"""
|
| 113 |
+
return "/storage/emulated/0/Projects"
|
| 114 |
+
|
| 115 |
+
@property
|
| 116 |
+
def user_publicshare_dir(self) -> str:
|
| 117 |
+
""":returns: public share directory tied to the user e.g. ``/storage/emulated/0/Public``"""
|
| 118 |
+
return "/storage/emulated/0/Public"
|
| 119 |
+
|
| 120 |
+
@property
|
| 121 |
+
def user_templates_dir(self) -> str:
|
| 122 |
+
""":returns: templates directory tied to the user e.g. ``/storage/emulated/0/Templates``"""
|
| 123 |
+
return "/storage/emulated/0/Templates"
|
| 124 |
+
|
| 125 |
+
@property
|
| 126 |
+
def user_fonts_dir(self) -> str:
|
| 127 |
+
""":returns: fonts directory tied to the user e.g. ``/storage/emulated/0/fonts``"""
|
| 128 |
+
return "/storage/emulated/0/fonts"
|
| 129 |
+
|
| 130 |
+
@property
|
| 131 |
+
def user_preference_dir(self) -> str:
|
| 132 |
+
""":returns: preference directory tied to the user, same as ``user_config_dir``"""
|
| 133 |
+
return self.user_config_dir
|
| 134 |
+
|
| 135 |
+
@property
|
| 136 |
+
def user_bin_dir(self) -> str:
|
| 137 |
+
""":returns: bin directory tied to the user, e.g. ``/data/user/<userid>/<packagename>/files/bin``"""
|
| 138 |
+
return os.path.join(cast("str", _android_folder()), "files", "bin") # noqa: PTH118
|
| 139 |
+
|
| 140 |
+
@property
|
| 141 |
+
def site_bin_dir(self) -> str:
|
| 142 |
+
""":returns: bin directory shared by users, same as `user_bin_dir`"""
|
| 143 |
+
return self.user_bin_dir
|
| 144 |
+
|
| 145 |
+
@property
|
| 146 |
+
def user_applications_dir(self) -> str:
|
| 147 |
+
""":returns: applications directory tied to the user, same as `user_data_dir`"""
|
| 148 |
+
return self.user_data_dir
|
| 149 |
+
|
| 150 |
+
@property
|
| 151 |
+
def site_applications_dir(self) -> str:
|
| 152 |
+
""":returns: applications directory shared by users, same as `user_applications_dir`"""
|
| 153 |
+
return self.user_applications_dir
|
| 154 |
+
|
| 155 |
+
@property
|
| 156 |
+
def user_runtime_dir(self) -> str:
|
| 157 |
+
""":returns: runtime directory tied to the user, same as `user_cache_dir` if not opinionated else ``tmp`` in it, e.g. ``/data/user/<userid>/<packagename>/cache/<AppName>/tmp``"""
|
| 158 |
+
path = self.user_cache_dir
|
| 159 |
+
if self.opinion:
|
| 160 |
+
path = os.path.join(path, "tmp") # noqa: PTH118
|
| 161 |
+
self._optionally_create_directory(path)
|
| 162 |
+
return path
|
| 163 |
+
|
| 164 |
+
@property
|
| 165 |
+
def site_runtime_dir(self) -> str:
|
| 166 |
+
""":returns: runtime directory shared by users, same as `user_runtime_dir`"""
|
| 167 |
+
return self.user_runtime_dir
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
@lru_cache(maxsize=1)
|
| 171 |
+
def _android_folder() -> str | None: # noqa: C901
|
| 172 |
+
""":returns: base folder for the Android OS or None if it cannot be found"""
|
| 173 |
+
result: str | None = None
|
| 174 |
+
# type checker isn't happy with our "import android", just don't do this when type checking see
|
| 175 |
+
# https://stackoverflow.com/a/61394121
|
| 176 |
+
if not TYPE_CHECKING:
|
| 177 |
+
try:
|
| 178 |
+
# First try to get a path to android app using python4android (if available)...
|
| 179 |
+
from android import mActivity # noqa: PLC0415
|
| 180 |
+
|
| 181 |
+
context = cast("android.content.Context", mActivity.getApplicationContext()) # noqa: F821
|
| 182 |
+
result = context.getFilesDir().getParentFile().getAbsolutePath()
|
| 183 |
+
except Exception: # noqa: BLE001
|
| 184 |
+
result = None
|
| 185 |
+
if result is None:
|
| 186 |
+
try:
|
| 187 |
+
# ...and fall back to using plain pyjnius, if python4android isn't available or doesn't deliver any useful
|
| 188 |
+
# result...
|
| 189 |
+
from jnius import autoclass # noqa: PLC0415 # ty: ignore[unresolved-import]
|
| 190 |
+
|
| 191 |
+
context = autoclass("android.content.Context")
|
| 192 |
+
result = context.getFilesDir().getParentFile().getAbsolutePath()
|
| 193 |
+
except Exception: # noqa: BLE001
|
| 194 |
+
result = None
|
| 195 |
+
if result is None:
|
| 196 |
+
# and if that fails, too, find an android folder looking at path on the sys.path
|
| 197 |
+
# warning: only works for apps installed under /data, not adopted storage etc.
|
| 198 |
+
pattern = re.compile(r"/data/(data|user/\d+)/(.+)/files")
|
| 199 |
+
for path in sys.path:
|
| 200 |
+
if pattern.match(path):
|
| 201 |
+
result = path.split("/files")[0]
|
| 202 |
+
break
|
| 203 |
+
else:
|
| 204 |
+
result = None
|
| 205 |
+
if result is None:
|
| 206 |
+
# one last try: find an android folder looking at path on the sys.path taking adopted storage paths into
|
| 207 |
+
# account
|
| 208 |
+
pattern = re.compile(r"/mnt/expand/[a-fA-F0-9-]{36}/(data|user/\d+)/(.+)/files")
|
| 209 |
+
for path in sys.path:
|
| 210 |
+
if pattern.match(path):
|
| 211 |
+
result = path.split("/files")[0]
|
| 212 |
+
break
|
| 213 |
+
else:
|
| 214 |
+
result = None
|
| 215 |
+
return result
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
@lru_cache(maxsize=1)
|
| 219 |
+
def _android_documents_folder() -> str:
|
| 220 |
+
""":returns: documents folder for the Android OS"""
|
| 221 |
+
# Get directories with pyjnius
|
| 222 |
+
try:
|
| 223 |
+
from jnius import autoclass # noqa: PLC0415 # ty: ignore[unresolved-import]
|
| 224 |
+
|
| 225 |
+
context = autoclass("android.content.Context")
|
| 226 |
+
environment = autoclass("android.os.Environment")
|
| 227 |
+
documents_dir: str = context.getExternalFilesDir(environment.DIRECTORY_DOCUMENTS).getAbsolutePath()
|
| 228 |
+
except Exception: # noqa: BLE001
|
| 229 |
+
documents_dir = "/storage/emulated/0/Documents"
|
| 230 |
+
|
| 231 |
+
return documents_dir
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
@lru_cache(maxsize=1)
|
| 235 |
+
def _android_downloads_folder() -> str:
|
| 236 |
+
""":returns: downloads folder for the Android OS"""
|
| 237 |
+
# Get directories with pyjnius
|
| 238 |
+
try:
|
| 239 |
+
from jnius import autoclass # noqa: PLC0415 # ty: ignore[unresolved-import]
|
| 240 |
+
|
| 241 |
+
context = autoclass("android.content.Context")
|
| 242 |
+
environment = autoclass("android.os.Environment")
|
| 243 |
+
downloads_dir: str = context.getExternalFilesDir(environment.DIRECTORY_DOWNLOADS).getAbsolutePath()
|
| 244 |
+
except Exception: # noqa: BLE001
|
| 245 |
+
downloads_dir = "/storage/emulated/0/Downloads"
|
| 246 |
+
|
| 247 |
+
return downloads_dir
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
@lru_cache(maxsize=1)
|
| 251 |
+
def _android_pictures_folder() -> str:
|
| 252 |
+
""":returns: pictures folder for the Android OS"""
|
| 253 |
+
# Get directories with pyjnius
|
| 254 |
+
try:
|
| 255 |
+
from jnius import autoclass # noqa: PLC0415 # ty: ignore[unresolved-import]
|
| 256 |
+
|
| 257 |
+
context = autoclass("android.content.Context")
|
| 258 |
+
environment = autoclass("android.os.Environment")
|
| 259 |
+
pictures_dir: str = context.getExternalFilesDir(environment.DIRECTORY_PICTURES).getAbsolutePath()
|
| 260 |
+
except Exception: # noqa: BLE001
|
| 261 |
+
pictures_dir = "/storage/emulated/0/Pictures"
|
| 262 |
+
|
| 263 |
+
return pictures_dir
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
@lru_cache(maxsize=1)
|
| 267 |
+
def _android_videos_folder() -> str:
|
| 268 |
+
""":returns: videos folder for the Android OS"""
|
| 269 |
+
# Get directories with pyjnius
|
| 270 |
+
try:
|
| 271 |
+
from jnius import autoclass # noqa: PLC0415 # ty: ignore[unresolved-import]
|
| 272 |
+
|
| 273 |
+
context = autoclass("android.content.Context")
|
| 274 |
+
environment = autoclass("android.os.Environment")
|
| 275 |
+
videos_dir: str = context.getExternalFilesDir(environment.DIRECTORY_DCIM).getAbsolutePath()
|
| 276 |
+
except Exception: # noqa: BLE001
|
| 277 |
+
videos_dir = "/storage/emulated/0/DCIM/Camera"
|
| 278 |
+
|
| 279 |
+
return videos_dir
|
| 280 |
+
|
| 281 |
+
|
| 282 |
+
@lru_cache(maxsize=1)
|
| 283 |
+
def _android_music_folder() -> str:
|
| 284 |
+
""":returns: music folder for the Android OS"""
|
| 285 |
+
# Get directories with pyjnius
|
| 286 |
+
try:
|
| 287 |
+
from jnius import autoclass # noqa: PLC0415 # ty: ignore[unresolved-import]
|
| 288 |
+
|
| 289 |
+
context = autoclass("android.content.Context")
|
| 290 |
+
environment = autoclass("android.os.Environment")
|
| 291 |
+
music_dir: str = context.getExternalFilesDir(environment.DIRECTORY_MUSIC).getAbsolutePath()
|
| 292 |
+
except Exception: # noqa: BLE001
|
| 293 |
+
music_dir = "/storage/emulated/0/Music"
|
| 294 |
+
|
| 295 |
+
return music_dir
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
__all__ = [
|
| 299 |
+
"Android",
|
| 300 |
+
]
|
.venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/api.py
ADDED
|
@@ -0,0 +1,463 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Base API."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
from abc import ABC, abstractmethod
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
from typing import TYPE_CHECKING
|
| 9 |
+
|
| 10 |
+
if TYPE_CHECKING:
|
| 11 |
+
from collections.abc import Iterator
|
| 12 |
+
from typing import Literal
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class PlatformDirsABC(ABC): # noqa: PLR0904
|
| 16 |
+
"""Abstract base class defining all platform directory properties, their :class:`~pathlib.Path` variants, and iterators.
|
| 17 |
+
|
| 18 |
+
Platform-specific subclasses (e.g. :class:`~platformdirs.windows.Windows`, :class:`~platformdirs.macos.MacOS`,
|
| 19 |
+
:class:`~platformdirs.unix.Unix`) implement the abstract properties to return the appropriate paths for each
|
| 20 |
+
operating system.
|
| 21 |
+
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
def __init__( # noqa: PLR0913, PLR0917
|
| 25 |
+
self,
|
| 26 |
+
appname: str | None = None,
|
| 27 |
+
appauthor: str | Literal[False] | None = None,
|
| 28 |
+
version: str | None = None,
|
| 29 |
+
roaming: bool = False, # noqa: FBT001, FBT002
|
| 30 |
+
multipath: bool = False, # noqa: FBT001, FBT002
|
| 31 |
+
opinion: bool = True, # noqa: FBT001, FBT002
|
| 32 |
+
ensure_exists: bool = False, # noqa: FBT001, FBT002
|
| 33 |
+
use_site_for_root: bool = False, # noqa: FBT001, FBT002
|
| 34 |
+
) -> None:
|
| 35 |
+
"""Create a new platform directory.
|
| 36 |
+
|
| 37 |
+
:param appname: See `appname`.
|
| 38 |
+
:param appauthor: See `appauthor`.
|
| 39 |
+
:param version: See `version`.
|
| 40 |
+
:param roaming: See `roaming`.
|
| 41 |
+
:param multipath: See `multipath`.
|
| 42 |
+
:param opinion: See `opinion`.
|
| 43 |
+
:param ensure_exists: See `ensure_exists`.
|
| 44 |
+
:param use_site_for_root: See `use_site_for_root`.
|
| 45 |
+
|
| 46 |
+
"""
|
| 47 |
+
self.appname = appname #: The name of the application.
|
| 48 |
+
self.appauthor = appauthor
|
| 49 |
+
"""The name of the app author or distributing body for this application.
|
| 50 |
+
|
| 51 |
+
Typically, it is the owning company name. Defaults to `appname`. You may pass ``False`` to disable it.
|
| 52 |
+
|
| 53 |
+
.. note::
|
| 54 |
+
|
| 55 |
+
On Windows, the directory structure is ``<base>/<appauthor>/<appname>``. When ``appauthor`` is ``None`` (the
|
| 56 |
+
default), it falls back to ``appname``, resulting in ``<base>/<appname>/<appname>`` (e.g.
|
| 57 |
+
``AppData/Local/myapp/myapp``). Pass ``appauthor=False`` to omit the author directory entirely and get
|
| 58 |
+
``<base>/<appname>``.
|
| 59 |
+
|
| 60 |
+
"""
|
| 61 |
+
self.version = version
|
| 62 |
+
"""An optional version path element to append to the path.
|
| 63 |
+
|
| 64 |
+
You might want to use this if you want multiple versions of your app to be able to run independently. If used,
|
| 65 |
+
this would typically be ``<major>.<minor>``.
|
| 66 |
+
|
| 67 |
+
"""
|
| 68 |
+
self.roaming = roaming
|
| 69 |
+
"""Whether to use the roaming appdata directory on Windows.
|
| 70 |
+
|
| 71 |
+
That means that for users on a Windows network setup for roaming profiles, this user data will be synced on
|
| 72 |
+
login (see `here <https://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>`_).
|
| 73 |
+
|
| 74 |
+
"""
|
| 75 |
+
self.multipath = multipath
|
| 76 |
+
"""An optional parameter which indicates that the entire list of data dirs should be returned.
|
| 77 |
+
|
| 78 |
+
By default, the first item would only be returned. Only affects ``site_data_dir`` and ``site_config_dir`` on
|
| 79 |
+
Unix and macOS.
|
| 80 |
+
|
| 81 |
+
"""
|
| 82 |
+
self.opinion = opinion
|
| 83 |
+
"""Whether to use opinionated values.
|
| 84 |
+
|
| 85 |
+
When enabled, appends an additional subdirectory for certain directories: e.g. ``Cache`` for cache and ``Logs``
|
| 86 |
+
for logs on Windows, ``log`` for logs on Unix.
|
| 87 |
+
|
| 88 |
+
"""
|
| 89 |
+
self.ensure_exists = ensure_exists
|
| 90 |
+
"""Optionally create the directory (and any missing parents) upon access if it does not exist.
|
| 91 |
+
|
| 92 |
+
By default, no directories are created.
|
| 93 |
+
|
| 94 |
+
"""
|
| 95 |
+
self.use_site_for_root = use_site_for_root
|
| 96 |
+
"""Whether to redirect ``user_*_dir`` calls to their ``site_*_dir`` equivalents when running as root (uid 0).
|
| 97 |
+
|
| 98 |
+
Only has an effect on Unix. Disabled by default for backwards compatibility. When enabled, XDG user environment
|
| 99 |
+
variables (e.g. ``XDG_DATA_HOME``) are bypassed for the redirected directories.
|
| 100 |
+
|
| 101 |
+
"""
|
| 102 |
+
|
| 103 |
+
def _append_app_name_and_version(self, *base: str) -> str:
|
| 104 |
+
params = list(base[1:])
|
| 105 |
+
if self.appname:
|
| 106 |
+
params.append(self.appname)
|
| 107 |
+
if self.version:
|
| 108 |
+
params.append(self.version)
|
| 109 |
+
path = os.path.join(base[0], *params) # noqa: PTH118
|
| 110 |
+
self._optionally_create_directory(path)
|
| 111 |
+
return path
|
| 112 |
+
|
| 113 |
+
def _optionally_create_directory(self, path: str) -> None:
|
| 114 |
+
if self.ensure_exists:
|
| 115 |
+
Path(path).mkdir(parents=True, exist_ok=True)
|
| 116 |
+
|
| 117 |
+
def _first_item_as_path_if_multipath(self, directory: str) -> Path:
|
| 118 |
+
if self.multipath:
|
| 119 |
+
# If multipath is True, the first path is returned.
|
| 120 |
+
directory = directory.partition(os.pathsep)[0]
|
| 121 |
+
return Path(directory)
|
| 122 |
+
|
| 123 |
+
@property
|
| 124 |
+
@abstractmethod
|
| 125 |
+
def user_data_dir(self) -> str:
|
| 126 |
+
""":returns: data directory tied to the user"""
|
| 127 |
+
|
| 128 |
+
@property
|
| 129 |
+
@abstractmethod
|
| 130 |
+
def site_data_dir(self) -> str:
|
| 131 |
+
""":returns: data directory shared by users"""
|
| 132 |
+
|
| 133 |
+
@property
|
| 134 |
+
def _site_data_dirs(self) -> list[str]:
|
| 135 |
+
raise NotImplementedError
|
| 136 |
+
|
| 137 |
+
@property
|
| 138 |
+
@abstractmethod
|
| 139 |
+
def user_config_dir(self) -> str:
|
| 140 |
+
""":returns: config directory tied to the user"""
|
| 141 |
+
|
| 142 |
+
@property
|
| 143 |
+
@abstractmethod
|
| 144 |
+
def site_config_dir(self) -> str:
|
| 145 |
+
""":returns: config directory shared by users"""
|
| 146 |
+
|
| 147 |
+
@property
|
| 148 |
+
def _site_config_dirs(self) -> list[str]:
|
| 149 |
+
raise NotImplementedError
|
| 150 |
+
|
| 151 |
+
@property
|
| 152 |
+
@abstractmethod
|
| 153 |
+
def user_cache_dir(self) -> str:
|
| 154 |
+
""":returns: cache directory tied to the user"""
|
| 155 |
+
|
| 156 |
+
@property
|
| 157 |
+
@abstractmethod
|
| 158 |
+
def site_cache_dir(self) -> str:
|
| 159 |
+
""":returns: cache directory shared by users"""
|
| 160 |
+
|
| 161 |
+
@property
|
| 162 |
+
@abstractmethod
|
| 163 |
+
def user_state_dir(self) -> str:
|
| 164 |
+
""":returns: state directory tied to the user"""
|
| 165 |
+
|
| 166 |
+
@property
|
| 167 |
+
@abstractmethod
|
| 168 |
+
def site_state_dir(self) -> str:
|
| 169 |
+
""":returns: state directory shared by users"""
|
| 170 |
+
|
| 171 |
+
@property
|
| 172 |
+
@abstractmethod
|
| 173 |
+
def user_log_dir(self) -> str:
|
| 174 |
+
""":returns: log directory tied to the user"""
|
| 175 |
+
|
| 176 |
+
@property
|
| 177 |
+
@abstractmethod
|
| 178 |
+
def site_log_dir(self) -> str:
|
| 179 |
+
""":returns: log directory shared by users"""
|
| 180 |
+
|
| 181 |
+
@property
|
| 182 |
+
@abstractmethod
|
| 183 |
+
def user_documents_dir(self) -> str:
|
| 184 |
+
""":returns: documents directory tied to the user"""
|
| 185 |
+
|
| 186 |
+
@property
|
| 187 |
+
@abstractmethod
|
| 188 |
+
def user_downloads_dir(self) -> str:
|
| 189 |
+
""":returns: downloads directory tied to the user"""
|
| 190 |
+
|
| 191 |
+
@property
|
| 192 |
+
@abstractmethod
|
| 193 |
+
def user_pictures_dir(self) -> str:
|
| 194 |
+
""":returns: pictures directory tied to the user"""
|
| 195 |
+
|
| 196 |
+
@property
|
| 197 |
+
@abstractmethod
|
| 198 |
+
def user_videos_dir(self) -> str:
|
| 199 |
+
""":returns: videos directory tied to the user"""
|
| 200 |
+
|
| 201 |
+
@property
|
| 202 |
+
@abstractmethod
|
| 203 |
+
def user_music_dir(self) -> str:
|
| 204 |
+
""":returns: music directory tied to the user"""
|
| 205 |
+
|
| 206 |
+
@property
|
| 207 |
+
@abstractmethod
|
| 208 |
+
def user_desktop_dir(self) -> str:
|
| 209 |
+
""":returns: desktop directory tied to the user"""
|
| 210 |
+
|
| 211 |
+
@property
|
| 212 |
+
@abstractmethod
|
| 213 |
+
def user_projects_dir(self) -> str:
|
| 214 |
+
""":returns: projects directory tied to the user"""
|
| 215 |
+
|
| 216 |
+
@property
|
| 217 |
+
@abstractmethod
|
| 218 |
+
def user_publicshare_dir(self) -> str:
|
| 219 |
+
""":returns: public share directory tied to the user"""
|
| 220 |
+
|
| 221 |
+
@property
|
| 222 |
+
@abstractmethod
|
| 223 |
+
def user_templates_dir(self) -> str:
|
| 224 |
+
""":returns: templates directory tied to the user"""
|
| 225 |
+
|
| 226 |
+
@property
|
| 227 |
+
@abstractmethod
|
| 228 |
+
def user_fonts_dir(self) -> str:
|
| 229 |
+
""":returns: fonts directory tied to the user"""
|
| 230 |
+
|
| 231 |
+
@property
|
| 232 |
+
@abstractmethod
|
| 233 |
+
def user_preference_dir(self) -> str:
|
| 234 |
+
""":returns: preference directory tied to the user"""
|
| 235 |
+
|
| 236 |
+
@property
|
| 237 |
+
@abstractmethod
|
| 238 |
+
def user_bin_dir(self) -> str:
|
| 239 |
+
""":returns: bin directory tied to the user"""
|
| 240 |
+
|
| 241 |
+
@property
|
| 242 |
+
@abstractmethod
|
| 243 |
+
def site_bin_dir(self) -> str:
|
| 244 |
+
""":returns: bin directory shared by users"""
|
| 245 |
+
|
| 246 |
+
@property
|
| 247 |
+
@abstractmethod
|
| 248 |
+
def user_applications_dir(self) -> str:
|
| 249 |
+
""":returns: applications directory tied to the user"""
|
| 250 |
+
|
| 251 |
+
@property
|
| 252 |
+
@abstractmethod
|
| 253 |
+
def site_applications_dir(self) -> str:
|
| 254 |
+
""":returns: applications directory shared by users"""
|
| 255 |
+
|
| 256 |
+
@property
|
| 257 |
+
def _site_applications_dirs(self) -> list[str]:
|
| 258 |
+
raise NotImplementedError
|
| 259 |
+
|
| 260 |
+
@property
|
| 261 |
+
@abstractmethod
|
| 262 |
+
def user_runtime_dir(self) -> str:
|
| 263 |
+
""":returns: runtime directory tied to the user"""
|
| 264 |
+
|
| 265 |
+
@property
|
| 266 |
+
@abstractmethod
|
| 267 |
+
def site_runtime_dir(self) -> str:
|
| 268 |
+
""":returns: runtime directory shared by users"""
|
| 269 |
+
|
| 270 |
+
@property
|
| 271 |
+
def user_data_path(self) -> Path:
|
| 272 |
+
""":returns: data path tied to the user"""
|
| 273 |
+
return Path(self.user_data_dir)
|
| 274 |
+
|
| 275 |
+
@property
|
| 276 |
+
def site_data_path(self) -> Path:
|
| 277 |
+
""":returns: data path shared by users"""
|
| 278 |
+
return Path(self.site_data_dir)
|
| 279 |
+
|
| 280 |
+
@property
|
| 281 |
+
def user_config_path(self) -> Path:
|
| 282 |
+
""":returns: config path tied to the user"""
|
| 283 |
+
return Path(self.user_config_dir)
|
| 284 |
+
|
| 285 |
+
@property
|
| 286 |
+
def site_config_path(self) -> Path:
|
| 287 |
+
""":returns: config path shared by users"""
|
| 288 |
+
return Path(self.site_config_dir)
|
| 289 |
+
|
| 290 |
+
@property
|
| 291 |
+
def user_cache_path(self) -> Path:
|
| 292 |
+
""":returns: cache path tied to the user"""
|
| 293 |
+
return Path(self.user_cache_dir)
|
| 294 |
+
|
| 295 |
+
@property
|
| 296 |
+
def site_cache_path(self) -> Path:
|
| 297 |
+
""":returns: cache path shared by users"""
|
| 298 |
+
return Path(self.site_cache_dir)
|
| 299 |
+
|
| 300 |
+
@property
|
| 301 |
+
def user_state_path(self) -> Path:
|
| 302 |
+
""":returns: state path tied to the user"""
|
| 303 |
+
return Path(self.user_state_dir)
|
| 304 |
+
|
| 305 |
+
@property
|
| 306 |
+
def site_state_path(self) -> Path:
|
| 307 |
+
""":returns: state path shared by users"""
|
| 308 |
+
return Path(self.site_state_dir)
|
| 309 |
+
|
| 310 |
+
@property
|
| 311 |
+
def user_log_path(self) -> Path:
|
| 312 |
+
""":returns: log path tied to the user"""
|
| 313 |
+
return Path(self.user_log_dir)
|
| 314 |
+
|
| 315 |
+
@property
|
| 316 |
+
def site_log_path(self) -> Path:
|
| 317 |
+
""":returns: log path shared by users"""
|
| 318 |
+
return Path(self.site_log_dir)
|
| 319 |
+
|
| 320 |
+
@property
|
| 321 |
+
def user_documents_path(self) -> Path:
|
| 322 |
+
""":returns: documents path tied to the user"""
|
| 323 |
+
return Path(self.user_documents_dir)
|
| 324 |
+
|
| 325 |
+
@property
|
| 326 |
+
def user_downloads_path(self) -> Path:
|
| 327 |
+
""":returns: downloads path tied to the user"""
|
| 328 |
+
return Path(self.user_downloads_dir)
|
| 329 |
+
|
| 330 |
+
@property
|
| 331 |
+
def user_pictures_path(self) -> Path:
|
| 332 |
+
""":returns: pictures path tied to the user"""
|
| 333 |
+
return Path(self.user_pictures_dir)
|
| 334 |
+
|
| 335 |
+
@property
|
| 336 |
+
def user_videos_path(self) -> Path:
|
| 337 |
+
""":returns: videos path tied to the user"""
|
| 338 |
+
return Path(self.user_videos_dir)
|
| 339 |
+
|
| 340 |
+
@property
|
| 341 |
+
def user_music_path(self) -> Path:
|
| 342 |
+
""":returns: music path tied to the user"""
|
| 343 |
+
return Path(self.user_music_dir)
|
| 344 |
+
|
| 345 |
+
@property
|
| 346 |
+
def user_desktop_path(self) -> Path:
|
| 347 |
+
""":returns: desktop path tied to the user"""
|
| 348 |
+
return Path(self.user_desktop_dir)
|
| 349 |
+
|
| 350 |
+
@property
|
| 351 |
+
def user_projects_path(self) -> Path:
|
| 352 |
+
""":returns: projects path tied to the user"""
|
| 353 |
+
return Path(self.user_projects_dir)
|
| 354 |
+
|
| 355 |
+
@property
|
| 356 |
+
def user_publicshare_path(self) -> Path:
|
| 357 |
+
""":returns: public share path tied to the user"""
|
| 358 |
+
return Path(self.user_publicshare_dir)
|
| 359 |
+
|
| 360 |
+
@property
|
| 361 |
+
def user_templates_path(self) -> Path:
|
| 362 |
+
""":returns: templates path tied to the user"""
|
| 363 |
+
return Path(self.user_templates_dir)
|
| 364 |
+
|
| 365 |
+
@property
|
| 366 |
+
def user_fonts_path(self) -> Path:
|
| 367 |
+
""":returns: fonts path tied to the user"""
|
| 368 |
+
return Path(self.user_fonts_dir)
|
| 369 |
+
|
| 370 |
+
@property
|
| 371 |
+
def user_preference_path(self) -> Path:
|
| 372 |
+
""":returns: preference path tied to the user"""
|
| 373 |
+
return Path(self.user_preference_dir)
|
| 374 |
+
|
| 375 |
+
@property
|
| 376 |
+
def user_bin_path(self) -> Path:
|
| 377 |
+
""":returns: bin path tied to the user"""
|
| 378 |
+
return Path(self.user_bin_dir)
|
| 379 |
+
|
| 380 |
+
@property
|
| 381 |
+
def site_bin_path(self) -> Path:
|
| 382 |
+
""":returns: bin path shared by users"""
|
| 383 |
+
return Path(self.site_bin_dir)
|
| 384 |
+
|
| 385 |
+
@property
|
| 386 |
+
def user_applications_path(self) -> Path:
|
| 387 |
+
""":returns: applications path tied to the user"""
|
| 388 |
+
return Path(self.user_applications_dir)
|
| 389 |
+
|
| 390 |
+
@property
|
| 391 |
+
def site_applications_path(self) -> Path:
|
| 392 |
+
""":returns: applications path shared by users"""
|
| 393 |
+
return Path(self.site_applications_dir)
|
| 394 |
+
|
| 395 |
+
@property
|
| 396 |
+
def user_runtime_path(self) -> Path:
|
| 397 |
+
""":returns: runtime path tied to the user"""
|
| 398 |
+
return Path(self.user_runtime_dir)
|
| 399 |
+
|
| 400 |
+
@property
|
| 401 |
+
def site_runtime_path(self) -> Path:
|
| 402 |
+
""":returns: runtime path shared by users"""
|
| 403 |
+
return Path(self.site_runtime_dir)
|
| 404 |
+
|
| 405 |
+
def iter_config_dirs(self) -> Iterator[str]:
|
| 406 |
+
""":yield: all user and site configuration directories."""
|
| 407 |
+
yield self.user_config_dir
|
| 408 |
+
yield self.site_config_dir
|
| 409 |
+
|
| 410 |
+
def iter_data_dirs(self) -> Iterator[str]:
|
| 411 |
+
""":yield: all user and site data directories."""
|
| 412 |
+
yield self.user_data_dir
|
| 413 |
+
yield self.site_data_dir
|
| 414 |
+
|
| 415 |
+
def iter_cache_dirs(self) -> Iterator[str]:
|
| 416 |
+
""":yield: all user and site cache directories."""
|
| 417 |
+
yield self.user_cache_dir
|
| 418 |
+
yield self.site_cache_dir
|
| 419 |
+
|
| 420 |
+
def iter_state_dirs(self) -> Iterator[str]:
|
| 421 |
+
""":yield: all user and site state directories."""
|
| 422 |
+
yield self.user_state_dir
|
| 423 |
+
yield self.site_state_dir
|
| 424 |
+
|
| 425 |
+
def iter_log_dirs(self) -> Iterator[str]:
|
| 426 |
+
""":yield: all user and site log directories."""
|
| 427 |
+
yield self.user_log_dir
|
| 428 |
+
yield self.site_log_dir
|
| 429 |
+
|
| 430 |
+
def iter_runtime_dirs(self) -> Iterator[str]:
|
| 431 |
+
""":yield: all user and site runtime directories."""
|
| 432 |
+
yield self.user_runtime_dir
|
| 433 |
+
yield self.site_runtime_dir
|
| 434 |
+
|
| 435 |
+
def iter_config_paths(self) -> Iterator[Path]:
|
| 436 |
+
""":yield: all user and site configuration paths."""
|
| 437 |
+
for path in self.iter_config_dirs():
|
| 438 |
+
yield Path(path)
|
| 439 |
+
|
| 440 |
+
def iter_data_paths(self) -> Iterator[Path]:
|
| 441 |
+
""":yield: all user and site data paths."""
|
| 442 |
+
for path in self.iter_data_dirs():
|
| 443 |
+
yield Path(path)
|
| 444 |
+
|
| 445 |
+
def iter_cache_paths(self) -> Iterator[Path]:
|
| 446 |
+
""":yield: all user and site cache paths."""
|
| 447 |
+
for path in self.iter_cache_dirs():
|
| 448 |
+
yield Path(path)
|
| 449 |
+
|
| 450 |
+
def iter_state_paths(self) -> Iterator[Path]:
|
| 451 |
+
""":yield: all user and site state paths."""
|
| 452 |
+
for path in self.iter_state_dirs():
|
| 453 |
+
yield Path(path)
|
| 454 |
+
|
| 455 |
+
def iter_log_paths(self) -> Iterator[Path]:
|
| 456 |
+
""":yield: all user and site log paths."""
|
| 457 |
+
for path in self.iter_log_dirs():
|
| 458 |
+
yield Path(path)
|
| 459 |
+
|
| 460 |
+
def iter_runtime_paths(self) -> Iterator[Path]:
|
| 461 |
+
""":yield: all user and site runtime paths."""
|
| 462 |
+
for path in self.iter_runtime_dirs():
|
| 463 |
+
yield Path(path)
|
.venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/macos.py
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""macOS."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import os.path
|
| 6 |
+
import sys
|
| 7 |
+
from typing import TYPE_CHECKING
|
| 8 |
+
|
| 9 |
+
if TYPE_CHECKING:
|
| 10 |
+
from collections.abc import Iterator
|
| 11 |
+
|
| 12 |
+
from ._xdg import XDGMixin
|
| 13 |
+
from .api import PlatformDirsABC
|
| 14 |
+
|
| 15 |
+
if TYPE_CHECKING:
|
| 16 |
+
from pathlib import Path
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class _MacOSDefaults(PlatformDirsABC): # noqa: PLR0904
|
| 20 |
+
"""Default platform directories for macOS without XDG environment variable overrides.
|
| 21 |
+
|
| 22 |
+
Follows the guidance from `Apple's File System Programming Guide
|
| 23 |
+
<https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html>`_.
|
| 24 |
+
The XDG env var handling is in :class:`~platformdirs._xdg.XDGMixin`.
|
| 25 |
+
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
def _base_user_app_support_dir(self) -> str:
|
| 29 |
+
return self._append_app_name_and_version(os.path.expanduser("~/Library/Application Support")) # noqa: PTH111
|
| 30 |
+
|
| 31 |
+
def _base_site_dirs(self) -> list[str]:
|
| 32 |
+
is_homebrew = "/opt/python" in sys.prefix
|
| 33 |
+
homebrew_prefix = sys.prefix.split("/opt/python")[0] if is_homebrew else ""
|
| 34 |
+
path_list = [self._append_app_name_and_version(f"{homebrew_prefix}/share")] if is_homebrew else []
|
| 35 |
+
path_list.append(self._append_app_name_and_version("/Library/Application Support"))
|
| 36 |
+
return path_list
|
| 37 |
+
|
| 38 |
+
@property
|
| 39 |
+
def user_data_dir(self) -> str:
|
| 40 |
+
""":returns: data directory tied to the user, e.g. ``~/Library/Application Support/$appname/$version``"""
|
| 41 |
+
return self._base_user_app_support_dir()
|
| 42 |
+
|
| 43 |
+
@property
|
| 44 |
+
def _site_data_dirs(self) -> list[str]:
|
| 45 |
+
return self._base_site_dirs()
|
| 46 |
+
|
| 47 |
+
@property
|
| 48 |
+
def site_data_path(self) -> Path:
|
| 49 |
+
""":returns: data path shared by users. Only return the first item, even if ``multipath`` is set to ``True``"""
|
| 50 |
+
return self._first_item_as_path_if_multipath(self.site_data_dir)
|
| 51 |
+
|
| 52 |
+
@property
|
| 53 |
+
def site_config_path(self) -> Path:
|
| 54 |
+
""":returns: config path shared by users. Only return the first item, even if ``multipath`` is set to ``True``"""
|
| 55 |
+
return self._first_item_as_path_if_multipath(self.site_config_dir)
|
| 56 |
+
|
| 57 |
+
@property
|
| 58 |
+
def user_config_dir(self) -> str:
|
| 59 |
+
""":returns: config directory tied to the user, same as `user_data_dir`"""
|
| 60 |
+
return self._base_user_app_support_dir()
|
| 61 |
+
|
| 62 |
+
@property
|
| 63 |
+
def _site_config_dirs(self) -> list[str]:
|
| 64 |
+
return self._base_site_dirs()
|
| 65 |
+
|
| 66 |
+
@property
|
| 67 |
+
def user_cache_dir(self) -> str:
|
| 68 |
+
""":returns: cache directory tied to the user, e.g. ``~/Library/Caches/$appname/$version``"""
|
| 69 |
+
return self._append_app_name_and_version(os.path.expanduser("~/Library/Caches")) # noqa: PTH111
|
| 70 |
+
|
| 71 |
+
@property
|
| 72 |
+
def site_cache_dir(self) -> str:
|
| 73 |
+
""":returns: cache directory shared by users, e.g. ``/Library/Caches/$appname/$version``. If we're using a Python binary managed by `Homebrew <https://brew.sh>`_, the directory will be under the Homebrew prefix, e.g. ``$homebrew_prefix/var/cache/$appname/$version``. If `multipath <platformdirs.api.PlatformDirsABC.multipath>` is enabled, and we're in Homebrew, the response is a multi-path string separated by ":", e.g. ``$homebrew_prefix/var/cache/$appname/$version:/Library/Caches/$appname/$version``"""
|
| 74 |
+
is_homebrew = "/opt/python" in sys.prefix
|
| 75 |
+
homebrew_prefix = sys.prefix.split("/opt/python")[0] if is_homebrew else ""
|
| 76 |
+
path_list = [self._append_app_name_and_version(f"{homebrew_prefix}/var/cache")] if is_homebrew else []
|
| 77 |
+
path_list.append(self._append_app_name_and_version("/Library/Caches"))
|
| 78 |
+
if self.multipath:
|
| 79 |
+
return os.pathsep.join(path_list)
|
| 80 |
+
return path_list[0]
|
| 81 |
+
|
| 82 |
+
@property
|
| 83 |
+
def site_cache_path(self) -> Path:
|
| 84 |
+
""":returns: cache path shared by users. Only return the first item, even if ``multipath`` is set to ``True``"""
|
| 85 |
+
return self._first_item_as_path_if_multipath(self.site_cache_dir)
|
| 86 |
+
|
| 87 |
+
@property
|
| 88 |
+
def user_state_dir(self) -> str:
|
| 89 |
+
""":returns: state directory tied to the user, same as `user_data_dir`"""
|
| 90 |
+
return self._base_user_app_support_dir()
|
| 91 |
+
|
| 92 |
+
@property
|
| 93 |
+
def site_state_dir(self) -> str:
|
| 94 |
+
""":returns: state directory shared by users, same as `site_data_dir`"""
|
| 95 |
+
return self._base_site_dirs()[0]
|
| 96 |
+
|
| 97 |
+
@property
|
| 98 |
+
def user_log_dir(self) -> str:
|
| 99 |
+
""":returns: log directory tied to the user, e.g. ``~/Library/Logs/$appname/$version``"""
|
| 100 |
+
return self._append_app_name_and_version(os.path.expanduser("~/Library/Logs")) # noqa: PTH111
|
| 101 |
+
|
| 102 |
+
@property
|
| 103 |
+
def site_log_dir(self) -> str:
|
| 104 |
+
""":returns: log directory shared by users, e.g. ``/Library/Logs/$appname/$version``"""
|
| 105 |
+
return self._append_app_name_and_version("/Library/Logs")
|
| 106 |
+
|
| 107 |
+
@property
|
| 108 |
+
def user_documents_dir(self) -> str:
|
| 109 |
+
""":returns: documents directory tied to the user, e.g. ``~/Documents``"""
|
| 110 |
+
return os.path.expanduser("~/Documents") # noqa: PTH111
|
| 111 |
+
|
| 112 |
+
@property
|
| 113 |
+
def user_downloads_dir(self) -> str:
|
| 114 |
+
""":returns: downloads directory tied to the user, e.g. ``~/Downloads``"""
|
| 115 |
+
return os.path.expanduser("~/Downloads") # noqa: PTH111
|
| 116 |
+
|
| 117 |
+
@property
|
| 118 |
+
def user_pictures_dir(self) -> str:
|
| 119 |
+
""":returns: pictures directory tied to the user, e.g. ``~/Pictures``"""
|
| 120 |
+
return os.path.expanduser("~/Pictures") # noqa: PTH111
|
| 121 |
+
|
| 122 |
+
@property
|
| 123 |
+
def user_videos_dir(self) -> str:
|
| 124 |
+
""":returns: videos directory tied to the user, e.g. ``~/Movies``"""
|
| 125 |
+
return os.path.expanduser("~/Movies") # noqa: PTH111
|
| 126 |
+
|
| 127 |
+
@property
|
| 128 |
+
def user_music_dir(self) -> str:
|
| 129 |
+
""":returns: music directory tied to the user, e.g. ``~/Music``"""
|
| 130 |
+
return os.path.expanduser("~/Music") # noqa: PTH111
|
| 131 |
+
|
| 132 |
+
@property
|
| 133 |
+
def user_desktop_dir(self) -> str:
|
| 134 |
+
""":returns: desktop directory tied to the user, e.g. ``~/Desktop``"""
|
| 135 |
+
return os.path.expanduser("~/Desktop") # noqa: PTH111
|
| 136 |
+
|
| 137 |
+
@property
|
| 138 |
+
def user_projects_dir(self) -> str:
|
| 139 |
+
""":returns: projects directory tied to the user, e.g. ``~/Projects``"""
|
| 140 |
+
return os.path.expanduser("~/Projects") # noqa: PTH111
|
| 141 |
+
|
| 142 |
+
@property
|
| 143 |
+
def user_publicshare_dir(self) -> str:
|
| 144 |
+
""":returns: public share directory tied to the user, e.g. ``~/Public``"""
|
| 145 |
+
return os.path.expanduser("~/Public") # noqa: PTH111 # API returns str, not Path
|
| 146 |
+
|
| 147 |
+
@property
|
| 148 |
+
def user_templates_dir(self) -> str:
|
| 149 |
+
""":returns: templates directory tied to the user, e.g. ``~/Templates``"""
|
| 150 |
+
return os.path.expanduser("~/Templates") # noqa: PTH111 # API returns str, not Path
|
| 151 |
+
|
| 152 |
+
@property
|
| 153 |
+
def user_fonts_dir(self) -> str:
|
| 154 |
+
""":returns: fonts directory tied to the user, e.g. ``~/Library/Fonts``"""
|
| 155 |
+
return os.path.expanduser("~/Library/Fonts") # noqa: PTH111 # API returns str, not Path
|
| 156 |
+
|
| 157 |
+
@property
|
| 158 |
+
def user_preference_dir(self) -> str:
|
| 159 |
+
""":returns: preference directory tied to the user, e.g. ``~/Library/Preferences/AppName``"""
|
| 160 |
+
return self._append_app_name_and_version(os.path.expanduser("~/Library/Preferences")) # noqa: PTH111 # API returns str, not Path
|
| 161 |
+
|
| 162 |
+
@property
|
| 163 |
+
def user_bin_dir(self) -> str:
|
| 164 |
+
""":returns: bin directory tied to the user, e.g. ``~/.local/bin``"""
|
| 165 |
+
return os.path.expanduser("~/.local/bin") # noqa: PTH111
|
| 166 |
+
|
| 167 |
+
@property
|
| 168 |
+
def site_bin_dir(self) -> str:
|
| 169 |
+
""":returns: bin directory shared by users, e.g. ``/usr/local/bin``"""
|
| 170 |
+
return "/usr/local/bin"
|
| 171 |
+
|
| 172 |
+
@property
|
| 173 |
+
def user_applications_dir(self) -> str:
|
| 174 |
+
""":returns: applications directory tied to the user, e.g. ``~/Applications``"""
|
| 175 |
+
return os.path.expanduser("~/Applications") # noqa: PTH111
|
| 176 |
+
|
| 177 |
+
@property
|
| 178 |
+
def _site_applications_dirs(self) -> list[str]:
|
| 179 |
+
return ["/Applications"]
|
| 180 |
+
|
| 181 |
+
@property
|
| 182 |
+
def site_applications_dir(self) -> str:
|
| 183 |
+
""":returns: applications directory shared by users, e.g. ``/Applications``"""
|
| 184 |
+
dirs = self._site_applications_dirs
|
| 185 |
+
return os.pathsep.join(dirs) if self.multipath else dirs[0]
|
| 186 |
+
|
| 187 |
+
@property
|
| 188 |
+
def user_runtime_dir(self) -> str:
|
| 189 |
+
""":returns: runtime directory tied to the user, e.g. ``~/Library/Caches/TemporaryItems/$appname/$version``"""
|
| 190 |
+
return self._append_app_name_and_version(os.path.expanduser("~/Library/Caches/TemporaryItems")) # noqa: PTH111
|
| 191 |
+
|
| 192 |
+
@property
|
| 193 |
+
def site_runtime_dir(self) -> str:
|
| 194 |
+
""":returns: runtime directory shared by users, same as `user_runtime_dir`"""
|
| 195 |
+
return self.user_runtime_dir
|
| 196 |
+
|
| 197 |
+
def iter_config_dirs(self) -> Iterator[str]:
|
| 198 |
+
""":yield: all user and site configuration directories."""
|
| 199 |
+
yield self.user_config_dir
|
| 200 |
+
yield from self._site_config_dirs
|
| 201 |
+
|
| 202 |
+
def iter_data_dirs(self) -> Iterator[str]:
|
| 203 |
+
""":yield: all user and site data directories."""
|
| 204 |
+
yield self.user_data_dir
|
| 205 |
+
yield from self._site_data_dirs
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
class MacOS(XDGMixin, _MacOSDefaults):
|
| 209 |
+
"""Platform directories for the macOS operating system.
|
| 210 |
+
|
| 211 |
+
Follows the guidance from `Apple documentation
|
| 212 |
+
<https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html>`_.
|
| 213 |
+
Makes use of the `appname <platformdirs.api.PlatformDirsABC.appname>`, `version
|
| 214 |
+
<platformdirs.api.PlatformDirsABC.version>`, `ensure_exists <platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 215 |
+
|
| 216 |
+
XDG environment variables (e.g. ``$XDG_DATA_HOME``) are supported and take precedence over macOS defaults.
|
| 217 |
+
|
| 218 |
+
"""
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
__all__ = [
|
| 222 |
+
"MacOS",
|
| 223 |
+
]
|
.venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/py.typed
ADDED
|
File without changes
|
.venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/unix.py
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Unix."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
import sys
|
| 7 |
+
from configparser import ConfigParser
|
| 8 |
+
from functools import cached_property
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
from tempfile import gettempdir
|
| 11 |
+
from typing import TYPE_CHECKING, NoReturn
|
| 12 |
+
|
| 13 |
+
from ._xdg import XDGMixin
|
| 14 |
+
from .api import PlatformDirsABC
|
| 15 |
+
|
| 16 |
+
if TYPE_CHECKING:
|
| 17 |
+
from collections.abc import Iterator
|
| 18 |
+
|
| 19 |
+
if sys.platform == "win32":
|
| 20 |
+
|
| 21 |
+
def getuid() -> NoReturn:
|
| 22 |
+
msg = "should only be used on Unix"
|
| 23 |
+
raise RuntimeError(msg)
|
| 24 |
+
|
| 25 |
+
else:
|
| 26 |
+
from os import getuid
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class _UnixDefaults(PlatformDirsABC): # noqa: PLR0904
|
| 30 |
+
"""Default directories for Unix/Linux without XDG environment variable overrides.
|
| 31 |
+
|
| 32 |
+
The XDG env var handling is in :class:`~platformdirs._xdg.XDGMixin`.
|
| 33 |
+
|
| 34 |
+
"""
|
| 35 |
+
|
| 36 |
+
@cached_property
|
| 37 |
+
def _use_site(self) -> bool:
|
| 38 |
+
return self.use_site_for_root and getuid() == 0
|
| 39 |
+
|
| 40 |
+
@property
|
| 41 |
+
def user_data_dir(self) -> str:
|
| 42 |
+
""":returns: data directory tied to the user, e.g. ``~/.local/share/$appname/$version`` or ``$XDG_DATA_HOME/$appname/$version``"""
|
| 43 |
+
return self._append_app_name_and_version(os.path.expanduser("~/.local/share")) # noqa: PTH111
|
| 44 |
+
|
| 45 |
+
@property
|
| 46 |
+
def _site_data_dirs(self) -> list[str]:
|
| 47 |
+
return [self._append_app_name_and_version("/usr/local/share"), self._append_app_name_and_version("/usr/share")]
|
| 48 |
+
|
| 49 |
+
@property
|
| 50 |
+
def user_config_dir(self) -> str:
|
| 51 |
+
""":returns: config directory tied to the user, e.g. ``~/.config/$appname/$version`` or ``$XDG_CONFIG_HOME/$appname/$version``"""
|
| 52 |
+
return self._append_app_name_and_version(os.path.expanduser("~/.config")) # noqa: PTH111
|
| 53 |
+
|
| 54 |
+
@property
|
| 55 |
+
def _site_config_dirs(self) -> list[str]:
|
| 56 |
+
return [self._append_app_name_and_version("/etc/xdg")]
|
| 57 |
+
|
| 58 |
+
@property
|
| 59 |
+
def user_cache_dir(self) -> str:
|
| 60 |
+
""":returns: cache directory tied to the user, e.g. ``~/.cache/$appname/$version`` or ``$XDG_CACHE_HOME/$appname/$version``"""
|
| 61 |
+
return self._append_app_name_and_version(os.path.expanduser("~/.cache")) # noqa: PTH111
|
| 62 |
+
|
| 63 |
+
@property
|
| 64 |
+
def site_cache_dir(self) -> str:
|
| 65 |
+
""":returns: cache directory shared by users, e.g. ``/var/cache/$appname/$version``"""
|
| 66 |
+
return self._append_app_name_and_version("/var/cache")
|
| 67 |
+
|
| 68 |
+
@property
|
| 69 |
+
def user_state_dir(self) -> str:
|
| 70 |
+
""":returns: state directory tied to the user, e.g. ``~/.local/state/$appname/$version`` or ``$XDG_STATE_HOME/$appname/$version``"""
|
| 71 |
+
return self._append_app_name_and_version(os.path.expanduser("~/.local/state")) # noqa: PTH111
|
| 72 |
+
|
| 73 |
+
@property
|
| 74 |
+
def site_state_dir(self) -> str:
|
| 75 |
+
""":returns: state directory shared by users, e.g. ``/var/lib/$appname/$version``"""
|
| 76 |
+
return self._append_app_name_and_version("/var/lib")
|
| 77 |
+
|
| 78 |
+
@property
|
| 79 |
+
def user_log_dir(self) -> str:
|
| 80 |
+
""":returns: log directory tied to the user, same as `user_state_dir` if not opinionated else ``log`` in it"""
|
| 81 |
+
path = self.user_state_dir
|
| 82 |
+
if self.opinion:
|
| 83 |
+
path = os.path.join(path, "log") # noqa: PTH118
|
| 84 |
+
self._optionally_create_directory(path)
|
| 85 |
+
return path
|
| 86 |
+
|
| 87 |
+
@property
|
| 88 |
+
def site_log_dir(self) -> str:
|
| 89 |
+
""":returns: log directory shared by users, e.g. ``/var/log/$appname/$version``
|
| 90 |
+
|
| 91 |
+
Unlike `user_log_dir`, ``opinion`` has no effect since ``/var/log`` is inherently a log directory.
|
| 92 |
+
|
| 93 |
+
"""
|
| 94 |
+
return self._append_app_name_and_version("/var/log")
|
| 95 |
+
|
| 96 |
+
@property
|
| 97 |
+
def user_documents_dir(self) -> str:
|
| 98 |
+
""":returns: documents directory tied to the user, e.g. ``~/Documents``"""
|
| 99 |
+
return _get_user_media_dir("XDG_DOCUMENTS_DIR", "~/Documents")
|
| 100 |
+
|
| 101 |
+
@property
|
| 102 |
+
def user_downloads_dir(self) -> str:
|
| 103 |
+
""":returns: downloads directory tied to the user, e.g. ``~/Downloads``"""
|
| 104 |
+
return _get_user_media_dir("XDG_DOWNLOAD_DIR", "~/Downloads")
|
| 105 |
+
|
| 106 |
+
@property
|
| 107 |
+
def user_pictures_dir(self) -> str:
|
| 108 |
+
""":returns: pictures directory tied to the user, e.g. ``~/Pictures``"""
|
| 109 |
+
return _get_user_media_dir("XDG_PICTURES_DIR", "~/Pictures")
|
| 110 |
+
|
| 111 |
+
@property
|
| 112 |
+
def user_videos_dir(self) -> str:
|
| 113 |
+
""":returns: videos directory tied to the user, e.g. ``~/Videos``"""
|
| 114 |
+
return _get_user_media_dir("XDG_VIDEOS_DIR", "~/Videos")
|
| 115 |
+
|
| 116 |
+
@property
|
| 117 |
+
def user_music_dir(self) -> str:
|
| 118 |
+
""":returns: music directory tied to the user, e.g. ``~/Music``"""
|
| 119 |
+
return _get_user_media_dir("XDG_MUSIC_DIR", "~/Music")
|
| 120 |
+
|
| 121 |
+
@property
|
| 122 |
+
def user_desktop_dir(self) -> str:
|
| 123 |
+
""":returns: desktop directory tied to the user, e.g. ``~/Desktop``"""
|
| 124 |
+
return _get_user_media_dir("XDG_DESKTOP_DIR", "~/Desktop")
|
| 125 |
+
|
| 126 |
+
@property
|
| 127 |
+
def user_projects_dir(self) -> str:
|
| 128 |
+
""":returns: projects directory tied to the user, e.g. ``~/Projects``"""
|
| 129 |
+
return _get_user_media_dir("XDG_PROJECTS_DIR", "~/Projects")
|
| 130 |
+
|
| 131 |
+
@property
|
| 132 |
+
def user_publicshare_dir(self) -> str:
|
| 133 |
+
""":returns: public share directory tied to the user, e.g. ``~/Public``"""
|
| 134 |
+
return _get_user_media_dir("XDG_PUBLICSHARE_DIR", "~/Public")
|
| 135 |
+
|
| 136 |
+
@property
|
| 137 |
+
def user_templates_dir(self) -> str:
|
| 138 |
+
""":returns: templates directory tied to the user, e.g. ``~/Templates``"""
|
| 139 |
+
return _get_user_media_dir("XDG_TEMPLATES_DIR", "~/Templates")
|
| 140 |
+
|
| 141 |
+
@property
|
| 142 |
+
def user_fonts_dir(self) -> str:
|
| 143 |
+
""":returns: fonts directory tied to the user, e.g. ``~/.local/share/fonts``"""
|
| 144 |
+
return f"{os.path.expanduser('~/.local/share')}/fonts" # noqa: PTH111 # API returns str, not Path
|
| 145 |
+
|
| 146 |
+
@property
|
| 147 |
+
def user_preference_dir(self) -> str:
|
| 148 |
+
""":returns: preference directory tied to the user, same as ``user_config_dir``"""
|
| 149 |
+
return self.user_config_dir
|
| 150 |
+
|
| 151 |
+
@property
|
| 152 |
+
def user_bin_dir(self) -> str:
|
| 153 |
+
""":returns: bin directory tied to the user, e.g. ``~/.local/bin``"""
|
| 154 |
+
return os.path.expanduser("~/.local/bin") # noqa: PTH111
|
| 155 |
+
|
| 156 |
+
@property
|
| 157 |
+
def site_bin_dir(self) -> str:
|
| 158 |
+
""":returns: bin directory shared by users, e.g. ``/usr/local/bin``"""
|
| 159 |
+
return "/usr/local/bin"
|
| 160 |
+
|
| 161 |
+
@property
|
| 162 |
+
def user_applications_dir(self) -> str:
|
| 163 |
+
""":returns: applications directory tied to the user, e.g. ``~/.local/share/applications``"""
|
| 164 |
+
return os.path.join(os.path.expanduser("~/.local/share"), "applications") # noqa: PTH111, PTH118
|
| 165 |
+
|
| 166 |
+
@property
|
| 167 |
+
def _site_applications_dirs(self) -> list[str]:
|
| 168 |
+
return [os.path.join(p, "applications") for p in ["/usr/local/share", "/usr/share"]] # noqa: PTH118
|
| 169 |
+
|
| 170 |
+
@property
|
| 171 |
+
def site_applications_dir(self) -> str:
|
| 172 |
+
""":returns: applications directory shared by users, e.g. ``/usr/share/applications``"""
|
| 173 |
+
dirs = self._site_applications_dirs
|
| 174 |
+
return os.pathsep.join(dirs) if self.multipath else dirs[0]
|
| 175 |
+
|
| 176 |
+
@property
|
| 177 |
+
def user_runtime_dir(self) -> str:
|
| 178 |
+
""":returns: runtime directory tied to the user, e.g. ``$XDG_RUNTIME_DIR/$appname/$version``.
|
| 179 |
+
|
| 180 |
+
If ``$XDG_RUNTIME_DIR`` is unset, tries the platform default (``/tmp/run/user/$(id -u)`` on OpenBSD, ``/var/run/user/$(id -u)`` on FreeBSD/NetBSD, ``/run/user/$(id -u)`` otherwise). If the default is not writable, falls back to a temporary directory.
|
| 181 |
+
|
| 182 |
+
"""
|
| 183 |
+
if sys.platform.startswith("openbsd"):
|
| 184 |
+
path = f"/tmp/run/user/{getuid()}" # noqa: S108
|
| 185 |
+
elif sys.platform.startswith(("freebsd", "netbsd")):
|
| 186 |
+
path = f"/var/run/user/{getuid()}"
|
| 187 |
+
else:
|
| 188 |
+
path = f"/run/user/{getuid()}"
|
| 189 |
+
if not os.access(path, os.W_OK):
|
| 190 |
+
path = f"{gettempdir()}/runtime-{getuid()}"
|
| 191 |
+
return self._append_app_name_and_version(path)
|
| 192 |
+
|
| 193 |
+
@property
|
| 194 |
+
def site_runtime_dir(self) -> str:
|
| 195 |
+
""":returns: runtime directory shared by users, e.g. ``/run/$appname/$version`` or ``$XDG_RUNTIME_DIR/$appname/$version``.
|
| 196 |
+
|
| 197 |
+
Note that this behaves almost exactly like `user_runtime_dir` if ``$XDG_RUNTIME_DIR`` is set, but will fall back to paths associated to the root user instead of a regular logged-in user if it's not set.
|
| 198 |
+
|
| 199 |
+
If you wish to ensure that a logged-in root user path is returned e.g. ``/run/user/0``, use `user_runtime_dir` instead.
|
| 200 |
+
|
| 201 |
+
For FreeBSD/OpenBSD/NetBSD, it would return ``/var/run/$appname/$version`` if ``$XDG_RUNTIME_DIR`` is not set.
|
| 202 |
+
|
| 203 |
+
"""
|
| 204 |
+
if sys.platform.startswith(("freebsd", "openbsd", "netbsd")):
|
| 205 |
+
path = "/var/run"
|
| 206 |
+
else:
|
| 207 |
+
path = "/run"
|
| 208 |
+
return self._append_app_name_and_version(path)
|
| 209 |
+
|
| 210 |
+
@property
|
| 211 |
+
def site_data_path(self) -> Path:
|
| 212 |
+
""":returns: data path shared by users. Only return the first item, even if ``multipath`` is set to ``True``"""
|
| 213 |
+
return self._first_item_as_path_if_multipath(self.site_data_dir)
|
| 214 |
+
|
| 215 |
+
@property
|
| 216 |
+
def site_config_path(self) -> Path:
|
| 217 |
+
""":returns: config path shared by users, returns the first item, even if ``multipath`` is set to ``True``"""
|
| 218 |
+
return self._first_item_as_path_if_multipath(self.site_config_dir)
|
| 219 |
+
|
| 220 |
+
@property
|
| 221 |
+
def site_cache_path(self) -> Path:
|
| 222 |
+
""":returns: cache path shared by users. Only return the first item, even if ``multipath`` is set to ``True``"""
|
| 223 |
+
return self._first_item_as_path_if_multipath(self.site_cache_dir)
|
| 224 |
+
|
| 225 |
+
def iter_config_dirs(self) -> Iterator[str]:
|
| 226 |
+
""":yield: all user and site configuration directories."""
|
| 227 |
+
if not self._use_site:
|
| 228 |
+
yield self.user_config_dir
|
| 229 |
+
yield from self._site_config_dirs
|
| 230 |
+
|
| 231 |
+
def iter_data_dirs(self) -> Iterator[str]:
|
| 232 |
+
""":yield: all user and site data directories."""
|
| 233 |
+
if not self._use_site:
|
| 234 |
+
yield self.user_data_dir
|
| 235 |
+
yield from self._site_data_dirs
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
class Unix(XDGMixin, _UnixDefaults):
|
| 239 |
+
"""On Unix/Linux, we follow the `XDG Basedir Spec <https://specifications.freedesktop.org/basedir/latest/>`_.
|
| 240 |
+
|
| 241 |
+
The spec allows overriding directories with environment variables. The examples shown are the default values,
|
| 242 |
+
alongside the name of the environment variable that overrides them. Makes use of the `appname
|
| 243 |
+
<platformdirs.api.PlatformDirsABC.appname>`, `version <platformdirs.api.PlatformDirsABC.version>`, `multipath
|
| 244 |
+
<platformdirs.api.PlatformDirsABC.multipath>`, `opinion <platformdirs.api.PlatformDirsABC.opinion>`, `ensure_exists
|
| 245 |
+
<platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 246 |
+
|
| 247 |
+
"""
|
| 248 |
+
|
| 249 |
+
@property
|
| 250 |
+
def user_data_dir(self) -> str:
|
| 251 |
+
""":returns: data directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
|
| 252 |
+
return self.site_data_dir if self._use_site else super().user_data_dir
|
| 253 |
+
|
| 254 |
+
@property
|
| 255 |
+
def user_config_dir(self) -> str:
|
| 256 |
+
""":returns: config directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
|
| 257 |
+
return self.site_config_dir if self._use_site else super().user_config_dir
|
| 258 |
+
|
| 259 |
+
@property
|
| 260 |
+
def user_cache_dir(self) -> str:
|
| 261 |
+
""":returns: cache directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
|
| 262 |
+
return self.site_cache_dir if self._use_site else super().user_cache_dir
|
| 263 |
+
|
| 264 |
+
@property
|
| 265 |
+
def user_state_dir(self) -> str:
|
| 266 |
+
""":returns: state directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
|
| 267 |
+
return self.site_state_dir if self._use_site else super().user_state_dir
|
| 268 |
+
|
| 269 |
+
@property
|
| 270 |
+
def user_log_dir(self) -> str:
|
| 271 |
+
""":returns: log directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
|
| 272 |
+
return self.site_log_dir if self._use_site else super().user_log_dir
|
| 273 |
+
|
| 274 |
+
@property
|
| 275 |
+
def user_applications_dir(self) -> str:
|
| 276 |
+
""":returns: applications directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
|
| 277 |
+
return self.site_applications_dir if self._use_site else super().user_applications_dir
|
| 278 |
+
|
| 279 |
+
@property
|
| 280 |
+
def user_runtime_dir(self) -> str:
|
| 281 |
+
""":returns: runtime directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
|
| 282 |
+
return self.site_runtime_dir if self._use_site else super().user_runtime_dir
|
| 283 |
+
|
| 284 |
+
@property
|
| 285 |
+
def user_bin_dir(self) -> str:
|
| 286 |
+
""":returns: bin directory tied to the user, or site equivalent when root with ``use_site_for_root``"""
|
| 287 |
+
return self.site_bin_dir if self._use_site else super().user_bin_dir
|
| 288 |
+
|
| 289 |
+
|
| 290 |
+
def _get_user_media_dir(env_var: str, fallback_tilde_path: str) -> str:
|
| 291 |
+
if media_dir := _get_user_dirs_folder(env_var):
|
| 292 |
+
return media_dir
|
| 293 |
+
return os.path.expanduser(fallback_tilde_path) # noqa: PTH111
|
| 294 |
+
|
| 295 |
+
|
| 296 |
+
def _get_user_dirs_folder(key: str) -> str | None:
|
| 297 |
+
"""Return directory from user-dirs.dirs config file.
|
| 298 |
+
|
| 299 |
+
See https://freedesktop.org/wiki/Software/xdg-user-dirs/.
|
| 300 |
+
|
| 301 |
+
"""
|
| 302 |
+
config_home = os.environ.get("XDG_CONFIG_HOME", "").strip() or os.path.expanduser("~/.config") # noqa: PTH111
|
| 303 |
+
user_dirs_config_path = Path(config_home) / "user-dirs.dirs"
|
| 304 |
+
if user_dirs_config_path.exists():
|
| 305 |
+
parser = ConfigParser()
|
| 306 |
+
|
| 307 |
+
with user_dirs_config_path.open() as stream:
|
| 308 |
+
parser.read_string(f"[top]\n{stream.read()}")
|
| 309 |
+
|
| 310 |
+
if key not in parser["top"]:
|
| 311 |
+
return None
|
| 312 |
+
|
| 313 |
+
path = parser["top"][key].strip('"')
|
| 314 |
+
return path.replace("$HOME", os.path.expanduser("~")) # noqa: PTH111
|
| 315 |
+
|
| 316 |
+
return None
|
| 317 |
+
|
| 318 |
+
|
| 319 |
+
__all__ = [
|
| 320 |
+
"Unix",
|
| 321 |
+
]
|
.venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/version.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# file generated by vcs-versioning
|
| 2 |
+
# don't change, don't track in version control
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
__all__ = [
|
| 6 |
+
"__version__",
|
| 7 |
+
"__version_tuple__",
|
| 8 |
+
"version",
|
| 9 |
+
"version_tuple",
|
| 10 |
+
"__commit_id__",
|
| 11 |
+
"commit_id",
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
version: str
|
| 15 |
+
__version__: str
|
| 16 |
+
__version_tuple__: tuple[int | str, ...]
|
| 17 |
+
version_tuple: tuple[int | str, ...]
|
| 18 |
+
commit_id: str | None
|
| 19 |
+
__commit_id__: str | None
|
| 20 |
+
|
| 21 |
+
__version__ = version = '4.10.0'
|
| 22 |
+
__version_tuple__ = version_tuple = (4, 10, 0)
|
| 23 |
+
|
| 24 |
+
__commit_id__ = commit_id = None
|
.venv/lib/python3.14/site-packages/pip/_vendor/platformdirs/windows.py
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Windows."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
import sys
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
from typing import TYPE_CHECKING, Final
|
| 9 |
+
|
| 10 |
+
from .api import PlatformDirsABC
|
| 11 |
+
|
| 12 |
+
if TYPE_CHECKING:
|
| 13 |
+
from collections.abc import Callable
|
| 14 |
+
|
| 15 |
+
# Not exposed by CPython; defined in the Windows SDK (shlobj_core.h)
|
| 16 |
+
_KF_FLAG_DONT_VERIFY: Final[int] = 0x00004000
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class Windows(PlatformDirsABC): # noqa: PLR0904
|
| 20 |
+
"""`MSDN on where to store app data files <https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid>`_.
|
| 21 |
+
|
| 22 |
+
Makes use of the `appname <platformdirs.api.PlatformDirsABC.appname>`, `appauthor
|
| 23 |
+
<platformdirs.api.PlatformDirsABC.appauthor>`, `version <platformdirs.api.PlatformDirsABC.version>`, `roaming
|
| 24 |
+
<platformdirs.api.PlatformDirsABC.roaming>`, `opinion <platformdirs.api.PlatformDirsABC.opinion>`, `ensure_exists
|
| 25 |
+
<platformdirs.api.PlatformDirsABC.ensure_exists>`.
|
| 26 |
+
|
| 27 |
+
"""
|
| 28 |
+
|
| 29 |
+
@property
|
| 30 |
+
def user_data_dir(self) -> str:
|
| 31 |
+
r""":returns: data directory tied to the user, e.g. ``%USERPROFILE%\AppData\Local\$appauthor\$appname`` (not roaming) or ``%USERPROFILE%\AppData\Roaming\$appauthor\$appname`` (roaming)"""
|
| 32 |
+
const = "CSIDL_APPDATA" if self.roaming else "CSIDL_LOCAL_APPDATA"
|
| 33 |
+
path = os.path.normpath(get_win_folder(const))
|
| 34 |
+
return self._append_parts(path)
|
| 35 |
+
|
| 36 |
+
def _append_parts(self, path: str, *, opinion_value: str | None = None) -> str:
|
| 37 |
+
params = []
|
| 38 |
+
if self.appname:
|
| 39 |
+
if self.appauthor is not False:
|
| 40 |
+
author = self.appauthor or self.appname
|
| 41 |
+
params.append(author)
|
| 42 |
+
params.append(self.appname)
|
| 43 |
+
if opinion_value is not None and self.opinion:
|
| 44 |
+
params.append(opinion_value)
|
| 45 |
+
if self.version:
|
| 46 |
+
params.append(self.version)
|
| 47 |
+
path = os.path.join(path, *params) # noqa: PTH118
|
| 48 |
+
self._optionally_create_directory(path)
|
| 49 |
+
return path
|
| 50 |
+
|
| 51 |
+
@property
|
| 52 |
+
def site_data_dir(self) -> str:
|
| 53 |
+
r""":returns: data directory shared by users, e.g. ``C:\ProgramData\$appauthor\$appname``"""
|
| 54 |
+
path = os.path.normpath(get_win_folder("CSIDL_COMMON_APPDATA"))
|
| 55 |
+
return self._append_parts(path)
|
| 56 |
+
|
| 57 |
+
@property
|
| 58 |
+
def user_config_dir(self) -> str:
|
| 59 |
+
""":returns: config directory tied to the user, same as `user_data_dir`"""
|
| 60 |
+
return self.user_data_dir
|
| 61 |
+
|
| 62 |
+
@property
|
| 63 |
+
def site_config_dir(self) -> str:
|
| 64 |
+
""":returns: config directory shared by users, same as `site_data_dir`"""
|
| 65 |
+
return self.site_data_dir
|
| 66 |
+
|
| 67 |
+
@property
|
| 68 |
+
def user_cache_dir(self) -> str:
|
| 69 |
+
r""":returns: cache directory tied to the user (if opinionated with ``Cache`` folder within ``$appname``) e.g. ``%USERPROFILE%\AppData\Local\$appauthor\$appname\Cache\$version``"""
|
| 70 |
+
path = os.path.normpath(get_win_folder("CSIDL_LOCAL_APPDATA"))
|
| 71 |
+
return self._append_parts(path, opinion_value="Cache")
|
| 72 |
+
|
| 73 |
+
@property
|
| 74 |
+
def site_cache_dir(self) -> str:
|
| 75 |
+
r""":returns: cache directory shared by users, e.g. ``C:\ProgramData\$appauthor\$appname\Cache\$version``"""
|
| 76 |
+
path = os.path.normpath(get_win_folder("CSIDL_COMMON_APPDATA"))
|
| 77 |
+
return self._append_parts(path, opinion_value="Cache")
|
| 78 |
+
|
| 79 |
+
@property
|
| 80 |
+
def user_state_dir(self) -> str:
|
| 81 |
+
""":returns: state directory tied to the user, same as `user_data_dir`"""
|
| 82 |
+
return self.user_data_dir
|
| 83 |
+
|
| 84 |
+
@property
|
| 85 |
+
def site_state_dir(self) -> str:
|
| 86 |
+
""":returns: state directory shared by users, same as `site_data_dir`"""
|
| 87 |
+
return self.site_data_dir
|
| 88 |
+
|
| 89 |
+
@property
|
| 90 |
+
def user_log_dir(self) -> str:
|
| 91 |
+
""":returns: log directory tied to the user, same as `user_data_dir` if not opinionated else ``Logs`` in it"""
|
| 92 |
+
path = self.user_data_dir
|
| 93 |
+
if self.opinion:
|
| 94 |
+
path = os.path.join(path, "Logs") # noqa: PTH118
|
| 95 |
+
self._optionally_create_directory(path)
|
| 96 |
+
return path
|
| 97 |
+
|
| 98 |
+
@property
|
| 99 |
+
def site_log_dir(self) -> str:
|
| 100 |
+
""":returns: log directory shared by users, same as `site_data_dir` if not opinionated else ``Logs`` in it"""
|
| 101 |
+
path = self.site_data_dir
|
| 102 |
+
if self.opinion:
|
| 103 |
+
path = os.path.join(path, "Logs") # noqa: PTH118
|
| 104 |
+
self._optionally_create_directory(path)
|
| 105 |
+
return path
|
| 106 |
+
|
| 107 |
+
@property
|
| 108 |
+
def user_documents_dir(self) -> str:
|
| 109 |
+
r""":returns: documents directory tied to the user e.g. ``%USERPROFILE%\Documents``"""
|
| 110 |
+
return os.path.normpath(get_win_folder("CSIDL_PERSONAL"))
|
| 111 |
+
|
| 112 |
+
@property
|
| 113 |
+
def user_downloads_dir(self) -> str:
|
| 114 |
+
r""":returns: downloads directory tied to the user e.g. ``%USERPROFILE%\Downloads``"""
|
| 115 |
+
return os.path.normpath(get_win_folder("CSIDL_DOWNLOADS"))
|
| 116 |
+
|
| 117 |
+
@property
|
| 118 |
+
def user_pictures_dir(self) -> str:
|
| 119 |
+
r""":returns: pictures directory tied to the user e.g. ``%USERPROFILE%\Pictures``"""
|
| 120 |
+
return os.path.normpath(get_win_folder("CSIDL_MYPICTURES"))
|
| 121 |
+
|
| 122 |
+
@property
|
| 123 |
+
def user_videos_dir(self) -> str:
|
| 124 |
+
r""":returns: videos directory tied to the user e.g. ``%USERPROFILE%\Videos``"""
|
| 125 |
+
return os.path.normpath(get_win_folder("CSIDL_MYVIDEO"))
|
| 126 |
+
|
| 127 |
+
@property
|
| 128 |
+
def user_music_dir(self) -> str:
|
| 129 |
+
r""":returns: music directory tied to the user e.g. ``%USERPROFILE%\Music``"""
|
| 130 |
+
return os.path.normpath(get_win_folder("CSIDL_MYMUSIC"))
|
| 131 |
+
|
| 132 |
+
@property
|
| 133 |
+
def user_desktop_dir(self) -> str:
|
| 134 |
+
r""":returns: desktop directory tied to the user, e.g. ``%USERPROFILE%\Desktop``"""
|
| 135 |
+
return os.path.normpath(get_win_folder("CSIDL_DESKTOPDIRECTORY"))
|
| 136 |
+
|
| 137 |
+
@property
|
| 138 |
+
def user_projects_dir(self) -> str:
|
| 139 |
+
r""":returns: projects directory tied to the user, e.g. ``%USERPROFILE%\Projects``"""
|
| 140 |
+
return os.path.normpath(os.path.expanduser("~/Projects")) # noqa: PTH111
|
| 141 |
+
|
| 142 |
+
@property
|
| 143 |
+
def user_publicshare_dir(self) -> str:
|
| 144 |
+
r""":returns: public share directory e.g. ``C:\Users\Public``"""
|
| 145 |
+
return os.path.normpath(os.environ.get("PUBLIC", str(Path("~").expanduser().parent / "Public")))
|
| 146 |
+
|
| 147 |
+
@property
|
| 148 |
+
def user_templates_dir(self) -> str:
|
| 149 |
+
r""":returns: templates directory tied to the user e.g. ``%APPDATA%\Microsoft\Windows\Templates``"""
|
| 150 |
+
return os.path.normpath(str(Path(get_win_folder("CSIDL_APPDATA")) / "Microsoft" / "Windows" / "Templates"))
|
| 151 |
+
|
| 152 |
+
@property
|
| 153 |
+
def user_fonts_dir(self) -> str:
|
| 154 |
+
r""":returns: fonts directory tied to the user e.g. ``%LOCALAPPDATA%\Microsoft\Windows\Fonts``"""
|
| 155 |
+
return os.path.normpath(str(Path(get_win_folder("CSIDL_LOCAL_APPDATA")) / "Microsoft" / "Windows" / "Fonts"))
|
| 156 |
+
|
| 157 |
+
@property
|
| 158 |
+
def user_preference_dir(self) -> str:
|
| 159 |
+
r""":returns: preference directory tied to the user, same as ``user_config_dir``"""
|
| 160 |
+
return self.user_config_dir
|
| 161 |
+
|
| 162 |
+
@property
|
| 163 |
+
def user_bin_dir(self) -> str:
|
| 164 |
+
r""":returns: bin directory tied to the user, e.g. ``%LOCALAPPDATA%\Programs``"""
|
| 165 |
+
return os.path.normpath(os.path.join(get_win_folder("CSIDL_LOCAL_APPDATA"), "Programs")) # noqa: PTH118
|
| 166 |
+
|
| 167 |
+
@property
|
| 168 |
+
def site_bin_dir(self) -> str:
|
| 169 |
+
""":returns: bin directory shared by users, e.g. ``C:\\ProgramData\bin``"""
|
| 170 |
+
return os.path.normpath(os.path.join(get_win_folder("CSIDL_COMMON_APPDATA"), "bin")) # noqa: PTH118
|
| 171 |
+
|
| 172 |
+
@property
|
| 173 |
+
def user_applications_dir(self) -> str:
|
| 174 |
+
r""":returns: applications directory tied to the user, e.g. ``Start Menu\Programs``"""
|
| 175 |
+
return os.path.normpath(get_win_folder("CSIDL_PROGRAMS"))
|
| 176 |
+
|
| 177 |
+
@property
|
| 178 |
+
def site_applications_dir(self) -> str:
|
| 179 |
+
r""":returns: applications directory shared by users, e.g. ``C:\ProgramData\Microsoft\Windows\Start Menu\Programs``"""
|
| 180 |
+
return os.path.normpath(get_win_folder("CSIDL_COMMON_PROGRAMS"))
|
| 181 |
+
|
| 182 |
+
@property
|
| 183 |
+
def user_runtime_dir(self) -> str:
|
| 184 |
+
r""":returns: runtime directory tied to the user, e.g. ``%USERPROFILE%\AppData\Local\Temp\$appauthor\$appname``"""
|
| 185 |
+
path = os.path.normpath(os.path.join(get_win_folder("CSIDL_LOCAL_APPDATA"), "Temp")) # noqa: PTH118
|
| 186 |
+
return self._append_parts(path)
|
| 187 |
+
|
| 188 |
+
@property
|
| 189 |
+
def site_runtime_dir(self) -> str:
|
| 190 |
+
""":returns: runtime directory shared by users, same as `user_runtime_dir`"""
|
| 191 |
+
return self.user_runtime_dir
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
def get_win_folder_from_env_vars(csidl_name: str) -> str:
|
| 195 |
+
"""Get folder from environment variables."""
|
| 196 |
+
result = get_win_folder_if_csidl_name_not_env_var(csidl_name)
|
| 197 |
+
if result is not None:
|
| 198 |
+
return result
|
| 199 |
+
|
| 200 |
+
env_var_name = {
|
| 201 |
+
"CSIDL_APPDATA": "APPDATA",
|
| 202 |
+
"CSIDL_COMMON_APPDATA": "ALLUSERSPROFILE",
|
| 203 |
+
"CSIDL_LOCAL_APPDATA": "LOCALAPPDATA",
|
| 204 |
+
}.get(csidl_name)
|
| 205 |
+
if env_var_name is None:
|
| 206 |
+
msg = f"Unknown CSIDL name: {csidl_name}"
|
| 207 |
+
raise ValueError(msg)
|
| 208 |
+
result = os.environ.get(env_var_name)
|
| 209 |
+
if result is None:
|
| 210 |
+
msg = f"Unset environment variable: {env_var_name}"
|
| 211 |
+
raise ValueError(msg)
|
| 212 |
+
return result
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
def get_win_folder_if_csidl_name_not_env_var(csidl_name: str) -> str | None: # noqa: PLR0911
|
| 216 |
+
"""Get a folder for a CSIDL name that does not exist as an environment variable."""
|
| 217 |
+
if csidl_name == "CSIDL_PERSONAL":
|
| 218 |
+
return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Documents") # noqa: PTH118
|
| 219 |
+
|
| 220 |
+
if csidl_name == "CSIDL_DOWNLOADS":
|
| 221 |
+
return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Downloads") # noqa: PTH118
|
| 222 |
+
|
| 223 |
+
if csidl_name == "CSIDL_MYPICTURES":
|
| 224 |
+
return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Pictures") # noqa: PTH118
|
| 225 |
+
|
| 226 |
+
if csidl_name == "CSIDL_MYVIDEO":
|
| 227 |
+
return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Videos") # noqa: PTH118
|
| 228 |
+
|
| 229 |
+
if csidl_name == "CSIDL_MYMUSIC":
|
| 230 |
+
return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Music") # noqa: PTH118
|
| 231 |
+
|
| 232 |
+
if csidl_name == "CSIDL_PROGRAMS":
|
| 233 |
+
return os.path.join( # noqa: PTH118
|
| 234 |
+
os.path.normpath(os.environ["APPDATA"]),
|
| 235 |
+
"Microsoft",
|
| 236 |
+
"Windows",
|
| 237 |
+
"Start Menu",
|
| 238 |
+
"Programs",
|
| 239 |
+
)
|
| 240 |
+
|
| 241 |
+
if csidl_name == "CSIDL_COMMON_PROGRAMS":
|
| 242 |
+
return os.path.join( # noqa: PTH118
|
| 243 |
+
os.path.normpath(os.environ.get("PROGRAMDATA", os.environ.get("ALLUSERSPROFILE", "C:\\ProgramData"))),
|
| 244 |
+
"Microsoft",
|
| 245 |
+
"Windows",
|
| 246 |
+
"Start Menu",
|
| 247 |
+
"Programs",
|
| 248 |
+
)
|
| 249 |
+
return None
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
def get_win_folder_from_registry(csidl_name: str) -> str:
|
| 253 |
+
"""Get folder from the registry.
|
| 254 |
+
|
| 255 |
+
This is a fallback technique at best. I'm not sure if using the registry for these guarantees us the correct answer
|
| 256 |
+
for all CSIDL_* names.
|
| 257 |
+
|
| 258 |
+
"""
|
| 259 |
+
machine_names = {
|
| 260 |
+
"CSIDL_COMMON_APPDATA",
|
| 261 |
+
"CSIDL_COMMON_PROGRAMS",
|
| 262 |
+
}
|
| 263 |
+
shell_folder_name = {
|
| 264 |
+
"CSIDL_APPDATA": "AppData",
|
| 265 |
+
"CSIDL_COMMON_APPDATA": "Common AppData",
|
| 266 |
+
"CSIDL_LOCAL_APPDATA": "Local AppData",
|
| 267 |
+
"CSIDL_PERSONAL": "Personal",
|
| 268 |
+
"CSIDL_DOWNLOADS": "{374DE290-123F-4565-9164-39C4925E467B}",
|
| 269 |
+
"CSIDL_MYPICTURES": "My Pictures",
|
| 270 |
+
"CSIDL_MYVIDEO": "My Video",
|
| 271 |
+
"CSIDL_MYMUSIC": "My Music",
|
| 272 |
+
"CSIDL_PROGRAMS": "Programs",
|
| 273 |
+
"CSIDL_COMMON_PROGRAMS": "Common Programs",
|
| 274 |
+
}.get(csidl_name)
|
| 275 |
+
if shell_folder_name is None:
|
| 276 |
+
msg = f"Unknown CSIDL name: {csidl_name}"
|
| 277 |
+
raise ValueError(msg)
|
| 278 |
+
if sys.platform != "win32": # only needed for mypy type checker to know that this code runs only on Windows
|
| 279 |
+
raise NotImplementedError
|
| 280 |
+
import winreg # noqa: PLC0415
|
| 281 |
+
|
| 282 |
+
# Use HKEY_LOCAL_MACHINE for system-wide folders, HKEY_CURRENT_USER for user-specific folders
|
| 283 |
+
hkey = winreg.HKEY_LOCAL_MACHINE if csidl_name in machine_names else winreg.HKEY_CURRENT_USER
|
| 284 |
+
|
| 285 |
+
key = winreg.OpenKey(hkey, r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
|
| 286 |
+
directory, _ = winreg.QueryValueEx(key, shell_folder_name)
|
| 287 |
+
return str(directory)
|
| 288 |
+
|
| 289 |
+
|
| 290 |
+
_KNOWN_FOLDER_GUIDS: dict[str, str] = {
|
| 291 |
+
"CSIDL_APPDATA": "{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}",
|
| 292 |
+
"CSIDL_COMMON_APPDATA": "{62AB5D82-FDC1-4DC3-A9DD-070D1D495D97}",
|
| 293 |
+
"CSIDL_LOCAL_APPDATA": "{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}",
|
| 294 |
+
"CSIDL_PERSONAL": "{FDD39AD0-238F-46AF-ADB4-6C85480369C7}",
|
| 295 |
+
"CSIDL_MYPICTURES": "{33E28130-4E1E-4676-835A-98395C3BC3BB}",
|
| 296 |
+
"CSIDL_MYVIDEO": "{18989B1D-99B5-455B-841C-AB7C74E4DDFC}",
|
| 297 |
+
"CSIDL_MYMUSIC": "{4BD8D571-6D19-48D3-BE97-422220080E43}",
|
| 298 |
+
"CSIDL_DOWNLOADS": "{374DE290-123F-4565-9164-39C4925E467B}",
|
| 299 |
+
"CSIDL_DESKTOPDIRECTORY": "{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}",
|
| 300 |
+
"CSIDL_PROGRAMS": "{A77F5D77-2E2B-44C3-A6A2-ABA601054A51}",
|
| 301 |
+
"CSIDL_COMMON_PROGRAMS": "{0139D44E-6AFE-49F2-8690-3DAFCAE6FFB8}",
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
def get_win_folder_via_ctypes(csidl_name: str) -> str:
|
| 306 |
+
"""Get folder via :func:`SHGetKnownFolderPath`.
|
| 307 |
+
|
| 308 |
+
See https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath.
|
| 309 |
+
|
| 310 |
+
"""
|
| 311 |
+
if sys.platform != "win32": # only needed for type checker to know that this code runs only on Windows
|
| 312 |
+
raise NotImplementedError
|
| 313 |
+
from ctypes import HRESULT, POINTER, Structure, WinDLL, byref, create_unicode_buffer, wintypes # noqa: PLC0415
|
| 314 |
+
|
| 315 |
+
class _GUID(Structure):
|
| 316 |
+
_fields_ = [
|
| 317 |
+
("Data1", wintypes.DWORD),
|
| 318 |
+
("Data2", wintypes.WORD),
|
| 319 |
+
("Data3", wintypes.WORD),
|
| 320 |
+
("Data4", wintypes.BYTE * 8),
|
| 321 |
+
]
|
| 322 |
+
|
| 323 |
+
ole32 = WinDLL("ole32")
|
| 324 |
+
ole32.CLSIDFromString.restype = HRESULT
|
| 325 |
+
ole32.CLSIDFromString.argtypes = [wintypes.LPCOLESTR, POINTER(_GUID)]
|
| 326 |
+
ole32.CoTaskMemFree.restype = None
|
| 327 |
+
ole32.CoTaskMemFree.argtypes = [wintypes.LPVOID]
|
| 328 |
+
|
| 329 |
+
shell32 = WinDLL("shell32")
|
| 330 |
+
shell32.SHGetKnownFolderPath.restype = HRESULT
|
| 331 |
+
shell32.SHGetKnownFolderPath.argtypes = [POINTER(_GUID), wintypes.DWORD, wintypes.HANDLE, POINTER(wintypes.LPWSTR)]
|
| 332 |
+
|
| 333 |
+
kernel32 = WinDLL("kernel32")
|
| 334 |
+
kernel32.GetShortPathNameW.restype = wintypes.DWORD
|
| 335 |
+
kernel32.GetShortPathNameW.argtypes = [wintypes.LPWSTR, wintypes.LPWSTR, wintypes.DWORD]
|
| 336 |
+
|
| 337 |
+
folder_guid = _KNOWN_FOLDER_GUIDS.get(csidl_name)
|
| 338 |
+
if folder_guid is None:
|
| 339 |
+
msg = f"Unknown CSIDL name: {csidl_name}"
|
| 340 |
+
raise ValueError(msg)
|
| 341 |
+
|
| 342 |
+
guid = _GUID()
|
| 343 |
+
ole32.CLSIDFromString(folder_guid, byref(guid))
|
| 344 |
+
|
| 345 |
+
path_ptr = wintypes.LPWSTR()
|
| 346 |
+
shell32.SHGetKnownFolderPath(byref(guid), _KF_FLAG_DONT_VERIFY, None, byref(path_ptr))
|
| 347 |
+
result = path_ptr.value
|
| 348 |
+
ole32.CoTaskMemFree(path_ptr)
|
| 349 |
+
|
| 350 |
+
if result is None:
|
| 351 |
+
msg = f"SHGetKnownFolderPath returned NULL for {csidl_name}"
|
| 352 |
+
raise ValueError(msg)
|
| 353 |
+
|
| 354 |
+
if any(ord(c) > 255 for c in result): # noqa: PLR2004
|
| 355 |
+
buf = create_unicode_buffer(1024)
|
| 356 |
+
if kernel32.GetShortPathNameW(result, buf, 1024):
|
| 357 |
+
result = buf.value
|
| 358 |
+
|
| 359 |
+
return result
|
| 360 |
+
|
| 361 |
+
|
| 362 |
+
def _pick_get_win_folder() -> Callable[[str], str]:
|
| 363 |
+
"""Select the best method to resolve Windows folder paths: ctypes, then registry, then environment variables."""
|
| 364 |
+
try:
|
| 365 |
+
import ctypes # noqa: PLC0415, F401
|
| 366 |
+
except ImportError:
|
| 367 |
+
pass
|
| 368 |
+
else:
|
| 369 |
+
return get_win_folder_via_ctypes
|
| 370 |
+
try:
|
| 371 |
+
import winreg # noqa: PLC0415, F401
|
| 372 |
+
except ImportError:
|
| 373 |
+
return get_win_folder_from_env_vars
|
| 374 |
+
else:
|
| 375 |
+
return get_win_folder_from_registry
|
| 376 |
+
|
| 377 |
+
|
| 378 |
+
_resolve_win_folder = _pick_get_win_folder()
|
| 379 |
+
|
| 380 |
+
|
| 381 |
+
def get_win_folder(csidl_name: str) -> str:
|
| 382 |
+
"""Get a Windows folder path, checking for ``WIN_PD_OVERRIDE_*`` environment variable overrides first.
|
| 383 |
+
|
| 384 |
+
For example, ``CSIDL_LOCAL_APPDATA`` can be overridden by setting ``WIN_PD_OVERRIDE_LOCAL_APPDATA``.
|
| 385 |
+
|
| 386 |
+
"""
|
| 387 |
+
env_var = f"WIN_PD_OVERRIDE_{csidl_name.removeprefix('CSIDL_')}"
|
| 388 |
+
if override := os.environ.get(env_var, "").strip():
|
| 389 |
+
return override
|
| 390 |
+
return _resolve_win_folder(csidl_name)
|
| 391 |
+
|
| 392 |
+
|
| 393 |
+
__all__ = [
|
| 394 |
+
"Windows",
|
| 395 |
+
]
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Copyright (c) 2006-2022 by the respective authors (see AUTHORS file).
|
| 2 |
+
All rights reserved.
|
| 3 |
+
|
| 4 |
+
Redistribution and use in source and binary forms, with or without
|
| 5 |
+
modification, are permitted provided that the following conditions are
|
| 6 |
+
met:
|
| 7 |
+
|
| 8 |
+
* Redistributions of source code must retain the above copyright
|
| 9 |
+
notice, this list of conditions and the following disclaimer.
|
| 10 |
+
|
| 11 |
+
* Redistributions in binary form must reproduce the above copyright
|
| 12 |
+
notice, this list of conditions and the following disclaimer in the
|
| 13 |
+
documentation and/or other materials provided with the distribution.
|
| 14 |
+
|
| 15 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 16 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 17 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 18 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 19 |
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 20 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 21 |
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| 22 |
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| 23 |
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 24 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 25 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/__init__.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Pygments
|
| 3 |
+
~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Pygments is a syntax highlighting package written in Python.
|
| 6 |
+
|
| 7 |
+
It is a generic syntax highlighter for general use in all kinds of software
|
| 8 |
+
such as forum systems, wikis or other applications that need to prettify
|
| 9 |
+
source code. Highlights are:
|
| 10 |
+
|
| 11 |
+
* a wide range of common languages and markup formats is supported
|
| 12 |
+
* special attention is paid to details, increasing quality by a fair amount
|
| 13 |
+
* support for new languages and formats are added easily
|
| 14 |
+
* a number of output formats, presently HTML, LaTeX, RTF, SVG, all image
|
| 15 |
+
formats that PIL supports, and ANSI sequences
|
| 16 |
+
* it is usable as a command-line tool and as a library
|
| 17 |
+
* ... and it highlights even Brainfuck!
|
| 18 |
+
|
| 19 |
+
The `Pygments master branch`_ is installable with ``easy_install Pygments==dev``.
|
| 20 |
+
|
| 21 |
+
.. _Pygments master branch:
|
| 22 |
+
https://github.com/pygments/pygments/archive/master.zip#egg=Pygments-dev
|
| 23 |
+
|
| 24 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 25 |
+
:license: BSD, see LICENSE for details.
|
| 26 |
+
"""
|
| 27 |
+
from io import StringIO, BytesIO
|
| 28 |
+
|
| 29 |
+
__version__ = '2.20.0'
|
| 30 |
+
__docformat__ = 'restructuredtext'
|
| 31 |
+
|
| 32 |
+
__all__ = ['lex', 'format', 'highlight']
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def lex(code, lexer):
|
| 36 |
+
"""
|
| 37 |
+
Lex `code` with the `lexer` (must be a `Lexer` instance)
|
| 38 |
+
and return an iterable of tokens. Currently, this only calls
|
| 39 |
+
`lexer.get_tokens()`.
|
| 40 |
+
"""
|
| 41 |
+
try:
|
| 42 |
+
return lexer.get_tokens(code)
|
| 43 |
+
except TypeError:
|
| 44 |
+
# Heuristic to catch a common mistake.
|
| 45 |
+
from pip._vendor.pygments.lexer import RegexLexer
|
| 46 |
+
if isinstance(lexer, type) and issubclass(lexer, RegexLexer):
|
| 47 |
+
raise TypeError('lex() argument must be a lexer instance, '
|
| 48 |
+
'not a class')
|
| 49 |
+
raise
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def format(tokens, formatter, outfile=None): # pylint: disable=redefined-builtin
|
| 53 |
+
"""
|
| 54 |
+
Format ``tokens`` (an iterable of tokens) with the formatter ``formatter``
|
| 55 |
+
(a `Formatter` instance).
|
| 56 |
+
|
| 57 |
+
If ``outfile`` is given and a valid file object (an object with a
|
| 58 |
+
``write`` method), the result will be written to it, otherwise it
|
| 59 |
+
is returned as a string.
|
| 60 |
+
"""
|
| 61 |
+
try:
|
| 62 |
+
if not outfile:
|
| 63 |
+
realoutfile = getattr(formatter, 'encoding', None) and BytesIO() or StringIO()
|
| 64 |
+
formatter.format(tokens, realoutfile)
|
| 65 |
+
return realoutfile.getvalue()
|
| 66 |
+
else:
|
| 67 |
+
formatter.format(tokens, outfile)
|
| 68 |
+
except TypeError:
|
| 69 |
+
# Heuristic to catch a common mistake.
|
| 70 |
+
from pip._vendor.pygments.formatter import Formatter
|
| 71 |
+
if isinstance(formatter, type) and issubclass(formatter, Formatter):
|
| 72 |
+
raise TypeError('format() argument must be a formatter instance, '
|
| 73 |
+
'not a class')
|
| 74 |
+
raise
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def highlight(code, lexer, formatter, outfile=None):
|
| 78 |
+
"""
|
| 79 |
+
This is the most high-level highlighting function. It combines `lex` and
|
| 80 |
+
`format` in one function.
|
| 81 |
+
"""
|
| 82 |
+
return format(lex(code, lexer), formatter, outfile)
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/__main__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.__main__
|
| 3 |
+
~~~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Main entry point for ``python -m pygments``.
|
| 6 |
+
|
| 7 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 8 |
+
:license: BSD, see LICENSE for details.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import sys
|
| 12 |
+
from pip._vendor.pygments.cmdline import main
|
| 13 |
+
|
| 14 |
+
try:
|
| 15 |
+
sys.exit(main(sys.argv))
|
| 16 |
+
except KeyboardInterrupt:
|
| 17 |
+
sys.exit(1)
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/console.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.console
|
| 3 |
+
~~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Format colored console output.
|
| 6 |
+
|
| 7 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 8 |
+
:license: BSD, see LICENSE for details.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
esc = "\x1b["
|
| 12 |
+
|
| 13 |
+
codes = {}
|
| 14 |
+
codes[""] = ""
|
| 15 |
+
codes["reset"] = esc + "39;49;00m"
|
| 16 |
+
|
| 17 |
+
codes["bold"] = esc + "01m"
|
| 18 |
+
codes["faint"] = esc + "02m"
|
| 19 |
+
codes["standout"] = esc + "03m"
|
| 20 |
+
codes["underline"] = esc + "04m"
|
| 21 |
+
codes["blink"] = esc + "05m"
|
| 22 |
+
codes["overline"] = esc + "06m"
|
| 23 |
+
|
| 24 |
+
dark_colors = ["black", "red", "green", "yellow", "blue",
|
| 25 |
+
"magenta", "cyan", "gray"]
|
| 26 |
+
light_colors = ["brightblack", "brightred", "brightgreen", "brightyellow", "brightblue",
|
| 27 |
+
"brightmagenta", "brightcyan", "white"]
|
| 28 |
+
|
| 29 |
+
x = 30
|
| 30 |
+
for dark, light in zip(dark_colors, light_colors):
|
| 31 |
+
codes[dark] = esc + "%im" % x
|
| 32 |
+
codes[light] = esc + "%im" % (60 + x)
|
| 33 |
+
x += 1
|
| 34 |
+
|
| 35 |
+
del dark, light, x
|
| 36 |
+
|
| 37 |
+
codes["white"] = codes["bold"]
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def reset_color():
|
| 41 |
+
return codes["reset"]
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def colorize(color_key, text):
|
| 45 |
+
return codes[color_key] + text + codes["reset"]
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def ansiformat(attr, text):
|
| 49 |
+
"""
|
| 50 |
+
Format ``text`` with a color and/or some attributes::
|
| 51 |
+
|
| 52 |
+
color normal color
|
| 53 |
+
*color* bold color
|
| 54 |
+
_color_ underlined color
|
| 55 |
+
+color+ blinking color
|
| 56 |
+
"""
|
| 57 |
+
result = []
|
| 58 |
+
if attr[:1] == attr[-1:] == '+':
|
| 59 |
+
result.append(codes['blink'])
|
| 60 |
+
attr = attr[1:-1]
|
| 61 |
+
if attr[:1] == attr[-1:] == '*':
|
| 62 |
+
result.append(codes['bold'])
|
| 63 |
+
attr = attr[1:-1]
|
| 64 |
+
if attr[:1] == attr[-1:] == '_':
|
| 65 |
+
result.append(codes['underline'])
|
| 66 |
+
attr = attr[1:-1]
|
| 67 |
+
result.append(codes[attr])
|
| 68 |
+
result.append(text)
|
| 69 |
+
result.append(codes['reset'])
|
| 70 |
+
return ''.join(result)
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/filter.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.filter
|
| 3 |
+
~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Module that implements the default filter.
|
| 6 |
+
|
| 7 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 8 |
+
:license: BSD, see LICENSE for details.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def apply_filters(stream, filters, lexer=None):
|
| 13 |
+
"""
|
| 14 |
+
Use this method to apply an iterable of filters to
|
| 15 |
+
a stream. If lexer is given it's forwarded to the
|
| 16 |
+
filter, otherwise the filter receives `None`.
|
| 17 |
+
"""
|
| 18 |
+
def _apply(filter_, stream):
|
| 19 |
+
yield from filter_.filter(lexer, stream)
|
| 20 |
+
for filter_ in filters:
|
| 21 |
+
stream = _apply(filter_, stream)
|
| 22 |
+
return stream
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def simplefilter(f):
|
| 26 |
+
"""
|
| 27 |
+
Decorator that converts a function into a filter::
|
| 28 |
+
|
| 29 |
+
@simplefilter
|
| 30 |
+
def lowercase(self, lexer, stream, options):
|
| 31 |
+
for ttype, value in stream:
|
| 32 |
+
yield ttype, value.lower()
|
| 33 |
+
"""
|
| 34 |
+
return type(f.__name__, (FunctionFilter,), {
|
| 35 |
+
'__module__': getattr(f, '__module__'),
|
| 36 |
+
'__doc__': f.__doc__,
|
| 37 |
+
'function': f,
|
| 38 |
+
})
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
class Filter:
|
| 42 |
+
"""
|
| 43 |
+
Default filter. Subclass this class or use the `simplefilter`
|
| 44 |
+
decorator to create own filters.
|
| 45 |
+
"""
|
| 46 |
+
|
| 47 |
+
def __init__(self, **options):
|
| 48 |
+
self.options = options
|
| 49 |
+
|
| 50 |
+
def filter(self, lexer, stream):
|
| 51 |
+
raise NotImplementedError()
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
class FunctionFilter(Filter):
|
| 55 |
+
"""
|
| 56 |
+
Abstract class used by `simplefilter` to create simple
|
| 57 |
+
function filters on the fly. The `simplefilter` decorator
|
| 58 |
+
automatically creates subclasses of this class for
|
| 59 |
+
functions passed to it.
|
| 60 |
+
"""
|
| 61 |
+
function = None
|
| 62 |
+
|
| 63 |
+
def __init__(self, **options):
|
| 64 |
+
if not hasattr(self, 'function'):
|
| 65 |
+
raise TypeError(f'{self.__class__.__name__!r} used without bound function')
|
| 66 |
+
Filter.__init__(self, **options)
|
| 67 |
+
|
| 68 |
+
def filter(self, lexer, stream):
|
| 69 |
+
# pylint: disable=not-callable
|
| 70 |
+
yield from self.function(lexer, stream, self.options)
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/filters/__init__.py
ADDED
|
@@ -0,0 +1,942 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.filters
|
| 3 |
+
~~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Module containing filter lookup functions and default
|
| 6 |
+
filters.
|
| 7 |
+
|
| 8 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 9 |
+
:license: BSD, see LICENSE for details.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import re
|
| 13 |
+
|
| 14 |
+
from pip._vendor.pygments.token import String, Comment, Keyword, Name, Error, Whitespace, \
|
| 15 |
+
string_to_tokentype
|
| 16 |
+
from pip._vendor.pygments.filter import Filter
|
| 17 |
+
from pip._vendor.pygments.util import get_list_opt, get_int_opt, get_bool_opt, \
|
| 18 |
+
get_choice_opt, ClassNotFound, OptionError
|
| 19 |
+
from pip._vendor.pygments.plugin import find_plugin_filters
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def find_filter_class(filtername):
|
| 23 |
+
"""Lookup a filter by name. Return None if not found."""
|
| 24 |
+
if filtername in FILTERS:
|
| 25 |
+
return FILTERS[filtername]
|
| 26 |
+
for name, cls in find_plugin_filters():
|
| 27 |
+
if name == filtername:
|
| 28 |
+
return cls
|
| 29 |
+
return None
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def get_filter_by_name(filtername, **options):
|
| 33 |
+
"""Return an instantiated filter.
|
| 34 |
+
|
| 35 |
+
Options are passed to the filter initializer if wanted.
|
| 36 |
+
Raise a ClassNotFound if not found.
|
| 37 |
+
"""
|
| 38 |
+
cls = find_filter_class(filtername)
|
| 39 |
+
if cls:
|
| 40 |
+
return cls(**options)
|
| 41 |
+
else:
|
| 42 |
+
raise ClassNotFound(f'filter {filtername!r} not found')
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def get_all_filters():
|
| 46 |
+
"""Return a generator of all filter names."""
|
| 47 |
+
yield from FILTERS
|
| 48 |
+
for name, _ in find_plugin_filters():
|
| 49 |
+
yield name
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _replace_special(ttype, value, regex, specialttype,
|
| 53 |
+
replacefunc=lambda x: x):
|
| 54 |
+
last = 0
|
| 55 |
+
for match in regex.finditer(value):
|
| 56 |
+
start, end = match.start(), match.end()
|
| 57 |
+
if start != last:
|
| 58 |
+
yield ttype, value[last:start]
|
| 59 |
+
yield specialttype, replacefunc(value[start:end])
|
| 60 |
+
last = end
|
| 61 |
+
if last != len(value):
|
| 62 |
+
yield ttype, value[last:]
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class CodeTagFilter(Filter):
|
| 66 |
+
"""Highlight special code tags in comments and docstrings.
|
| 67 |
+
|
| 68 |
+
Options accepted:
|
| 69 |
+
|
| 70 |
+
`codetags` : list of strings
|
| 71 |
+
A list of strings that are flagged as code tags. The default is to
|
| 72 |
+
highlight ``XXX``, ``TODO``, ``FIXME``, ``BUG`` and ``NOTE``.
|
| 73 |
+
|
| 74 |
+
.. versionchanged:: 2.13
|
| 75 |
+
Now recognizes ``FIXME`` by default.
|
| 76 |
+
"""
|
| 77 |
+
|
| 78 |
+
def __init__(self, **options):
|
| 79 |
+
Filter.__init__(self, **options)
|
| 80 |
+
tags = get_list_opt(options, 'codetags',
|
| 81 |
+
['XXX', 'TODO', 'FIXME', 'BUG', 'NOTE'])
|
| 82 |
+
self.tag_re = re.compile(r'\b({})\b'.format('|'.join([
|
| 83 |
+
re.escape(tag) for tag in tags if tag
|
| 84 |
+
])))
|
| 85 |
+
|
| 86 |
+
def filter(self, lexer, stream):
|
| 87 |
+
regex = self.tag_re
|
| 88 |
+
for ttype, value in stream:
|
| 89 |
+
if ttype in String.Doc or \
|
| 90 |
+
ttype in Comment and \
|
| 91 |
+
ttype not in Comment.Preproc:
|
| 92 |
+
yield from _replace_special(ttype, value, regex, Comment.Special)
|
| 93 |
+
else:
|
| 94 |
+
yield ttype, value
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
class SymbolFilter(Filter):
|
| 98 |
+
"""Convert mathematical symbols into Unicode characters.
|
| 99 |
+
|
| 100 |
+
Examples are ``\\<longrightarrow>`` in Isabelle or
|
| 101 |
+
``\\longrightarrow`` in LaTeX.
|
| 102 |
+
|
| 103 |
+
This is mostly useful for HTML or console output when you want to
|
| 104 |
+
approximate the source rendering you'd see in an IDE.
|
| 105 |
+
|
| 106 |
+
Options accepted:
|
| 107 |
+
|
| 108 |
+
`lang` : string
|
| 109 |
+
The symbol language. Must be one of ``'isabelle'`` or
|
| 110 |
+
``'latex'``. The default is ``'isabelle'``.
|
| 111 |
+
"""
|
| 112 |
+
|
| 113 |
+
latex_symbols = {
|
| 114 |
+
'\\alpha' : '\U000003b1',
|
| 115 |
+
'\\beta' : '\U000003b2',
|
| 116 |
+
'\\gamma' : '\U000003b3',
|
| 117 |
+
'\\delta' : '\U000003b4',
|
| 118 |
+
'\\varepsilon' : '\U000003b5',
|
| 119 |
+
'\\zeta' : '\U000003b6',
|
| 120 |
+
'\\eta' : '\U000003b7',
|
| 121 |
+
'\\vartheta' : '\U000003b8',
|
| 122 |
+
'\\iota' : '\U000003b9',
|
| 123 |
+
'\\kappa' : '\U000003ba',
|
| 124 |
+
'\\lambda' : '\U000003bb',
|
| 125 |
+
'\\mu' : '\U000003bc',
|
| 126 |
+
'\\nu' : '\U000003bd',
|
| 127 |
+
'\\xi' : '\U000003be',
|
| 128 |
+
'\\pi' : '\U000003c0',
|
| 129 |
+
'\\varrho' : '\U000003c1',
|
| 130 |
+
'\\sigma' : '\U000003c3',
|
| 131 |
+
'\\tau' : '\U000003c4',
|
| 132 |
+
'\\upsilon' : '\U000003c5',
|
| 133 |
+
'\\varphi' : '\U000003c6',
|
| 134 |
+
'\\chi' : '\U000003c7',
|
| 135 |
+
'\\psi' : '\U000003c8',
|
| 136 |
+
'\\omega' : '\U000003c9',
|
| 137 |
+
'\\Gamma' : '\U00000393',
|
| 138 |
+
'\\Delta' : '\U00000394',
|
| 139 |
+
'\\Theta' : '\U00000398',
|
| 140 |
+
'\\Lambda' : '\U0000039b',
|
| 141 |
+
'\\Xi' : '\U0000039e',
|
| 142 |
+
'\\Pi' : '\U000003a0',
|
| 143 |
+
'\\Sigma' : '\U000003a3',
|
| 144 |
+
'\\Upsilon' : '\U000003a5',
|
| 145 |
+
'\\Phi' : '\U000003a6',
|
| 146 |
+
'\\Psi' : '\U000003a8',
|
| 147 |
+
'\\Omega' : '\U000003a9',
|
| 148 |
+
'\\leftarrow' : '\U00002190',
|
| 149 |
+
'\\longleftarrow' : '\U000027f5',
|
| 150 |
+
'\\rightarrow' : '\U00002192',
|
| 151 |
+
'\\longrightarrow' : '\U000027f6',
|
| 152 |
+
'\\Leftarrow' : '\U000021d0',
|
| 153 |
+
'\\Longleftarrow' : '\U000027f8',
|
| 154 |
+
'\\Rightarrow' : '\U000021d2',
|
| 155 |
+
'\\Longrightarrow' : '\U000027f9',
|
| 156 |
+
'\\leftrightarrow' : '\U00002194',
|
| 157 |
+
'\\longleftrightarrow' : '\U000027f7',
|
| 158 |
+
'\\Leftrightarrow' : '\U000021d4',
|
| 159 |
+
'\\Longleftrightarrow' : '\U000027fa',
|
| 160 |
+
'\\mapsto' : '\U000021a6',
|
| 161 |
+
'\\longmapsto' : '\U000027fc',
|
| 162 |
+
'\\relbar' : '\U00002500',
|
| 163 |
+
'\\Relbar' : '\U00002550',
|
| 164 |
+
'\\hookleftarrow' : '\U000021a9',
|
| 165 |
+
'\\hookrightarrow' : '\U000021aa',
|
| 166 |
+
'\\leftharpoondown' : '\U000021bd',
|
| 167 |
+
'\\rightharpoondown' : '\U000021c1',
|
| 168 |
+
'\\leftharpoonup' : '\U000021bc',
|
| 169 |
+
'\\rightharpoonup' : '\U000021c0',
|
| 170 |
+
'\\rightleftharpoons' : '\U000021cc',
|
| 171 |
+
'\\leadsto' : '\U0000219d',
|
| 172 |
+
'\\downharpoonleft' : '\U000021c3',
|
| 173 |
+
'\\downharpoonright' : '\U000021c2',
|
| 174 |
+
'\\upharpoonleft' : '\U000021bf',
|
| 175 |
+
'\\upharpoonright' : '\U000021be',
|
| 176 |
+
'\\restriction' : '\U000021be',
|
| 177 |
+
'\\uparrow' : '\U00002191',
|
| 178 |
+
'\\Uparrow' : '\U000021d1',
|
| 179 |
+
'\\downarrow' : '\U00002193',
|
| 180 |
+
'\\Downarrow' : '\U000021d3',
|
| 181 |
+
'\\updownarrow' : '\U00002195',
|
| 182 |
+
'\\Updownarrow' : '\U000021d5',
|
| 183 |
+
'\\langle' : '\U000027e8',
|
| 184 |
+
'\\rangle' : '\U000027e9',
|
| 185 |
+
'\\lceil' : '\U00002308',
|
| 186 |
+
'\\rceil' : '\U00002309',
|
| 187 |
+
'\\lfloor' : '\U0000230a',
|
| 188 |
+
'\\rfloor' : '\U0000230b',
|
| 189 |
+
'\\flqq' : '\U000000ab',
|
| 190 |
+
'\\frqq' : '\U000000bb',
|
| 191 |
+
'\\bot' : '\U000022a5',
|
| 192 |
+
'\\top' : '\U000022a4',
|
| 193 |
+
'\\wedge' : '\U00002227',
|
| 194 |
+
'\\bigwedge' : '\U000022c0',
|
| 195 |
+
'\\vee' : '\U00002228',
|
| 196 |
+
'\\bigvee' : '\U000022c1',
|
| 197 |
+
'\\forall' : '\U00002200',
|
| 198 |
+
'\\exists' : '\U00002203',
|
| 199 |
+
'\\nexists' : '\U00002204',
|
| 200 |
+
'\\neg' : '\U000000ac',
|
| 201 |
+
'\\Box' : '\U000025a1',
|
| 202 |
+
'\\Diamond' : '\U000025c7',
|
| 203 |
+
'\\vdash' : '\U000022a2',
|
| 204 |
+
'\\models' : '\U000022a8',
|
| 205 |
+
'\\dashv' : '\U000022a3',
|
| 206 |
+
'\\surd' : '\U0000221a',
|
| 207 |
+
'\\le' : '\U00002264',
|
| 208 |
+
'\\ge' : '\U00002265',
|
| 209 |
+
'\\ll' : '\U0000226a',
|
| 210 |
+
'\\gg' : '\U0000226b',
|
| 211 |
+
'\\lesssim' : '\U00002272',
|
| 212 |
+
'\\gtrsim' : '\U00002273',
|
| 213 |
+
'\\lessapprox' : '\U00002a85',
|
| 214 |
+
'\\gtrapprox' : '\U00002a86',
|
| 215 |
+
'\\in' : '\U00002208',
|
| 216 |
+
'\\notin' : '\U00002209',
|
| 217 |
+
'\\subset' : '\U00002282',
|
| 218 |
+
'\\supset' : '\U00002283',
|
| 219 |
+
'\\subseteq' : '\U00002286',
|
| 220 |
+
'\\supseteq' : '\U00002287',
|
| 221 |
+
'\\sqsubset' : '\U0000228f',
|
| 222 |
+
'\\sqsupset' : '\U00002290',
|
| 223 |
+
'\\sqsubseteq' : '\U00002291',
|
| 224 |
+
'\\sqsupseteq' : '\U00002292',
|
| 225 |
+
'\\cap' : '\U00002229',
|
| 226 |
+
'\\bigcap' : '\U000022c2',
|
| 227 |
+
'\\cup' : '\U0000222a',
|
| 228 |
+
'\\bigcup' : '\U000022c3',
|
| 229 |
+
'\\sqcup' : '\U00002294',
|
| 230 |
+
'\\bigsqcup' : '\U00002a06',
|
| 231 |
+
'\\sqcap' : '\U00002293',
|
| 232 |
+
'\\Bigsqcap' : '\U00002a05',
|
| 233 |
+
'\\setminus' : '\U00002216',
|
| 234 |
+
'\\propto' : '\U0000221d',
|
| 235 |
+
'\\uplus' : '\U0000228e',
|
| 236 |
+
'\\bigplus' : '\U00002a04',
|
| 237 |
+
'\\sim' : '\U0000223c',
|
| 238 |
+
'\\doteq' : '\U00002250',
|
| 239 |
+
'\\simeq' : '\U00002243',
|
| 240 |
+
'\\approx' : '\U00002248',
|
| 241 |
+
'\\asymp' : '\U0000224d',
|
| 242 |
+
'\\cong' : '\U00002245',
|
| 243 |
+
'\\equiv' : '\U00002261',
|
| 244 |
+
'\\Join' : '\U000022c8',
|
| 245 |
+
'\\bowtie' : '\U00002a1d',
|
| 246 |
+
'\\prec' : '\U0000227a',
|
| 247 |
+
'\\succ' : '\U0000227b',
|
| 248 |
+
'\\preceq' : '\U0000227c',
|
| 249 |
+
'\\succeq' : '\U0000227d',
|
| 250 |
+
'\\parallel' : '\U00002225',
|
| 251 |
+
'\\mid' : '\U000000a6',
|
| 252 |
+
'\\pm' : '\U000000b1',
|
| 253 |
+
'\\mp' : '\U00002213',
|
| 254 |
+
'\\times' : '\U000000d7',
|
| 255 |
+
'\\div' : '\U000000f7',
|
| 256 |
+
'\\cdot' : '\U000022c5',
|
| 257 |
+
'\\star' : '\U000022c6',
|
| 258 |
+
'\\circ' : '\U00002218',
|
| 259 |
+
'\\dagger' : '\U00002020',
|
| 260 |
+
'\\ddagger' : '\U00002021',
|
| 261 |
+
'\\lhd' : '\U000022b2',
|
| 262 |
+
'\\rhd' : '\U000022b3',
|
| 263 |
+
'\\unlhd' : '\U000022b4',
|
| 264 |
+
'\\unrhd' : '\U000022b5',
|
| 265 |
+
'\\triangleleft' : '\U000025c3',
|
| 266 |
+
'\\triangleright' : '\U000025b9',
|
| 267 |
+
'\\triangle' : '\U000025b3',
|
| 268 |
+
'\\triangleq' : '\U0000225c',
|
| 269 |
+
'\\oplus' : '\U00002295',
|
| 270 |
+
'\\bigoplus' : '\U00002a01',
|
| 271 |
+
'\\otimes' : '\U00002297',
|
| 272 |
+
'\\bigotimes' : '\U00002a02',
|
| 273 |
+
'\\odot' : '\U00002299',
|
| 274 |
+
'\\bigodot' : '\U00002a00',
|
| 275 |
+
'\\ominus' : '\U00002296',
|
| 276 |
+
'\\oslash' : '\U00002298',
|
| 277 |
+
'\\dots' : '\U00002026',
|
| 278 |
+
'\\cdots' : '\U000022ef',
|
| 279 |
+
'\\sum' : '\U00002211',
|
| 280 |
+
'\\prod' : '\U0000220f',
|
| 281 |
+
'\\coprod' : '\U00002210',
|
| 282 |
+
'\\infty' : '\U0000221e',
|
| 283 |
+
'\\int' : '\U0000222b',
|
| 284 |
+
'\\oint' : '\U0000222e',
|
| 285 |
+
'\\clubsuit' : '\U00002663',
|
| 286 |
+
'\\diamondsuit' : '\U00002662',
|
| 287 |
+
'\\heartsuit' : '\U00002661',
|
| 288 |
+
'\\spadesuit' : '\U00002660',
|
| 289 |
+
'\\aleph' : '\U00002135',
|
| 290 |
+
'\\emptyset' : '\U00002205',
|
| 291 |
+
'\\nabla' : '\U00002207',
|
| 292 |
+
'\\partial' : '\U00002202',
|
| 293 |
+
'\\flat' : '\U0000266d',
|
| 294 |
+
'\\natural' : '\U0000266e',
|
| 295 |
+
'\\sharp' : '\U0000266f',
|
| 296 |
+
'\\angle' : '\U00002220',
|
| 297 |
+
'\\copyright' : '\U000000a9',
|
| 298 |
+
'\\textregistered' : '\U000000ae',
|
| 299 |
+
'\\textonequarter' : '\U000000bc',
|
| 300 |
+
'\\textonehalf' : '\U000000bd',
|
| 301 |
+
'\\textthreequarters' : '\U000000be',
|
| 302 |
+
'\\textordfeminine' : '\U000000aa',
|
| 303 |
+
'\\textordmasculine' : '\U000000ba',
|
| 304 |
+
'\\euro' : '\U000020ac',
|
| 305 |
+
'\\pounds' : '\U000000a3',
|
| 306 |
+
'\\yen' : '\U000000a5',
|
| 307 |
+
'\\textcent' : '\U000000a2',
|
| 308 |
+
'\\textcurrency' : '\U000000a4',
|
| 309 |
+
'\\textdegree' : '\U000000b0',
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
isabelle_symbols = {
|
| 313 |
+
'\\<zero>' : '\U0001d7ec',
|
| 314 |
+
'\\<one>' : '\U0001d7ed',
|
| 315 |
+
'\\<two>' : '\U0001d7ee',
|
| 316 |
+
'\\<three>' : '\U0001d7ef',
|
| 317 |
+
'\\<four>' : '\U0001d7f0',
|
| 318 |
+
'\\<five>' : '\U0001d7f1',
|
| 319 |
+
'\\<six>' : '\U0001d7f2',
|
| 320 |
+
'\\<seven>' : '\U0001d7f3',
|
| 321 |
+
'\\<eight>' : '\U0001d7f4',
|
| 322 |
+
'\\<nine>' : '\U0001d7f5',
|
| 323 |
+
'\\<A>' : '\U0001d49c',
|
| 324 |
+
'\\<B>' : '\U0000212c',
|
| 325 |
+
'\\<C>' : '\U0001d49e',
|
| 326 |
+
'\\<D>' : '\U0001d49f',
|
| 327 |
+
'\\<E>' : '\U00002130',
|
| 328 |
+
'\\<F>' : '\U00002131',
|
| 329 |
+
'\\<G>' : '\U0001d4a2',
|
| 330 |
+
'\\<H>' : '\U0000210b',
|
| 331 |
+
'\\<I>' : '\U00002110',
|
| 332 |
+
'\\<J>' : '\U0001d4a5',
|
| 333 |
+
'\\<K>' : '\U0001d4a6',
|
| 334 |
+
'\\<L>' : '\U00002112',
|
| 335 |
+
'\\<M>' : '\U00002133',
|
| 336 |
+
'\\<N>' : '\U0001d4a9',
|
| 337 |
+
'\\<O>' : '\U0001d4aa',
|
| 338 |
+
'\\<P>' : '\U0001d4ab',
|
| 339 |
+
'\\<Q>' : '\U0001d4ac',
|
| 340 |
+
'\\<R>' : '\U0000211b',
|
| 341 |
+
'\\<S>' : '\U0001d4ae',
|
| 342 |
+
'\\<T>' : '\U0001d4af',
|
| 343 |
+
'\\<U>' : '\U0001d4b0',
|
| 344 |
+
'\\<V>' : '\U0001d4b1',
|
| 345 |
+
'\\<W>' : '\U0001d4b2',
|
| 346 |
+
'\\<X>' : '\U0001d4b3',
|
| 347 |
+
'\\<Y>' : '\U0001d4b4',
|
| 348 |
+
'\\<Z>' : '\U0001d4b5',
|
| 349 |
+
'\\<a>' : '\U0001d5ba',
|
| 350 |
+
'\\<b>' : '\U0001d5bb',
|
| 351 |
+
'\\<c>' : '\U0001d5bc',
|
| 352 |
+
'\\<d>' : '\U0001d5bd',
|
| 353 |
+
'\\<e>' : '\U0001d5be',
|
| 354 |
+
'\\<f>' : '\U0001d5bf',
|
| 355 |
+
'\\<g>' : '\U0001d5c0',
|
| 356 |
+
'\\<h>' : '\U0001d5c1',
|
| 357 |
+
'\\<i>' : '\U0001d5c2',
|
| 358 |
+
'\\<j>' : '\U0001d5c3',
|
| 359 |
+
'\\<k>' : '\U0001d5c4',
|
| 360 |
+
'\\<l>' : '\U0001d5c5',
|
| 361 |
+
'\\<m>' : '\U0001d5c6',
|
| 362 |
+
'\\<n>' : '\U0001d5c7',
|
| 363 |
+
'\\<o>' : '\U0001d5c8',
|
| 364 |
+
'\\<p>' : '\U0001d5c9',
|
| 365 |
+
'\\<q>' : '\U0001d5ca',
|
| 366 |
+
'\\<r>' : '\U0001d5cb',
|
| 367 |
+
'\\<s>' : '\U0001d5cc',
|
| 368 |
+
'\\<t>' : '\U0001d5cd',
|
| 369 |
+
'\\<u>' : '\U0001d5ce',
|
| 370 |
+
'\\<v>' : '\U0001d5cf',
|
| 371 |
+
'\\<w>' : '\U0001d5d0',
|
| 372 |
+
'\\<x>' : '\U0001d5d1',
|
| 373 |
+
'\\<y>' : '\U0001d5d2',
|
| 374 |
+
'\\<z>' : '\U0001d5d3',
|
| 375 |
+
'\\<AA>' : '\U0001d504',
|
| 376 |
+
'\\<BB>' : '\U0001d505',
|
| 377 |
+
'\\<CC>' : '\U0000212d',
|
| 378 |
+
'\\<DD>' : '\U0001d507',
|
| 379 |
+
'\\<EE>' : '\U0001d508',
|
| 380 |
+
'\\<FF>' : '\U0001d509',
|
| 381 |
+
'\\<GG>' : '\U0001d50a',
|
| 382 |
+
'\\<HH>' : '\U0000210c',
|
| 383 |
+
'\\<II>' : '\U00002111',
|
| 384 |
+
'\\<JJ>' : '\U0001d50d',
|
| 385 |
+
'\\<KK>' : '\U0001d50e',
|
| 386 |
+
'\\<LL>' : '\U0001d50f',
|
| 387 |
+
'\\<MM>' : '\U0001d510',
|
| 388 |
+
'\\<NN>' : '\U0001d511',
|
| 389 |
+
'\\<OO>' : '\U0001d512',
|
| 390 |
+
'\\<PP>' : '\U0001d513',
|
| 391 |
+
'\\<QQ>' : '\U0001d514',
|
| 392 |
+
'\\<RR>' : '\U0000211c',
|
| 393 |
+
'\\<SS>' : '\U0001d516',
|
| 394 |
+
'\\<TT>' : '\U0001d517',
|
| 395 |
+
'\\<UU>' : '\U0001d518',
|
| 396 |
+
'\\<VV>' : '\U0001d519',
|
| 397 |
+
'\\<WW>' : '\U0001d51a',
|
| 398 |
+
'\\<XX>' : '\U0001d51b',
|
| 399 |
+
'\\<YY>' : '\U0001d51c',
|
| 400 |
+
'\\<ZZ>' : '\U00002128',
|
| 401 |
+
'\\<aa>' : '\U0001d51e',
|
| 402 |
+
'\\<bb>' : '\U0001d51f',
|
| 403 |
+
'\\<cc>' : '\U0001d520',
|
| 404 |
+
'\\<dd>' : '\U0001d521',
|
| 405 |
+
'\\<ee>' : '\U0001d522',
|
| 406 |
+
'\\<ff>' : '\U0001d523',
|
| 407 |
+
'\\<gg>' : '\U0001d524',
|
| 408 |
+
'\\<hh>' : '\U0001d525',
|
| 409 |
+
'\\<ii>' : '\U0001d526',
|
| 410 |
+
'\\<jj>' : '\U0001d527',
|
| 411 |
+
'\\<kk>' : '\U0001d528',
|
| 412 |
+
'\\<ll>' : '\U0001d529',
|
| 413 |
+
'\\<mm>' : '\U0001d52a',
|
| 414 |
+
'\\<nn>' : '\U0001d52b',
|
| 415 |
+
'\\<oo>' : '\U0001d52c',
|
| 416 |
+
'\\<pp>' : '\U0001d52d',
|
| 417 |
+
'\\<qq>' : '\U0001d52e',
|
| 418 |
+
'\\<rr>' : '\U0001d52f',
|
| 419 |
+
'\\<ss>' : '\U0001d530',
|
| 420 |
+
'\\<tt>' : '\U0001d531',
|
| 421 |
+
'\\<uu>' : '\U0001d532',
|
| 422 |
+
'\\<vv>' : '\U0001d533',
|
| 423 |
+
'\\<ww>' : '\U0001d534',
|
| 424 |
+
'\\<xx>' : '\U0001d535',
|
| 425 |
+
'\\<yy>' : '\U0001d536',
|
| 426 |
+
'\\<zz>' : '\U0001d537',
|
| 427 |
+
'\\<alpha>' : '\U000003b1',
|
| 428 |
+
'\\<beta>' : '\U000003b2',
|
| 429 |
+
'\\<gamma>' : '\U000003b3',
|
| 430 |
+
'\\<delta>' : '\U000003b4',
|
| 431 |
+
'\\<epsilon>' : '\U000003b5',
|
| 432 |
+
'\\<zeta>' : '\U000003b6',
|
| 433 |
+
'\\<eta>' : '\U000003b7',
|
| 434 |
+
'\\<theta>' : '\U000003b8',
|
| 435 |
+
'\\<iota>' : '\U000003b9',
|
| 436 |
+
'\\<kappa>' : '\U000003ba',
|
| 437 |
+
'\\<lambda>' : '\U000003bb',
|
| 438 |
+
'\\<mu>' : '\U000003bc',
|
| 439 |
+
'\\<nu>' : '\U000003bd',
|
| 440 |
+
'\\<xi>' : '\U000003be',
|
| 441 |
+
'\\<pi>' : '\U000003c0',
|
| 442 |
+
'\\<rho>' : '\U000003c1',
|
| 443 |
+
'\\<sigma>' : '\U000003c3',
|
| 444 |
+
'\\<tau>' : '\U000003c4',
|
| 445 |
+
'\\<upsilon>' : '\U000003c5',
|
| 446 |
+
'\\<phi>' : '\U000003c6',
|
| 447 |
+
'\\<chi>' : '\U000003c7',
|
| 448 |
+
'\\<psi>' : '\U000003c8',
|
| 449 |
+
'\\<omega>' : '\U000003c9',
|
| 450 |
+
'\\<Gamma>' : '\U00000393',
|
| 451 |
+
'\\<Delta>' : '\U00000394',
|
| 452 |
+
'\\<Theta>' : '\U00000398',
|
| 453 |
+
'\\<Lambda>' : '\U0000039b',
|
| 454 |
+
'\\<Xi>' : '\U0000039e',
|
| 455 |
+
'\\<Pi>' : '\U000003a0',
|
| 456 |
+
'\\<Sigma>' : '\U000003a3',
|
| 457 |
+
'\\<Upsilon>' : '\U000003a5',
|
| 458 |
+
'\\<Phi>' : '\U000003a6',
|
| 459 |
+
'\\<Psi>' : '\U000003a8',
|
| 460 |
+
'\\<Omega>' : '\U000003a9',
|
| 461 |
+
'\\<bool>' : '\U0001d539',
|
| 462 |
+
'\\<complex>' : '\U00002102',
|
| 463 |
+
'\\<nat>' : '\U00002115',
|
| 464 |
+
'\\<rat>' : '\U0000211a',
|
| 465 |
+
'\\<real>' : '\U0000211d',
|
| 466 |
+
'\\<int>' : '\U00002124',
|
| 467 |
+
'\\<leftarrow>' : '\U00002190',
|
| 468 |
+
'\\<longleftarrow>' : '\U000027f5',
|
| 469 |
+
'\\<rightarrow>' : '\U00002192',
|
| 470 |
+
'\\<longrightarrow>' : '\U000027f6',
|
| 471 |
+
'\\<Leftarrow>' : '\U000021d0',
|
| 472 |
+
'\\<Longleftarrow>' : '\U000027f8',
|
| 473 |
+
'\\<Rightarrow>' : '\U000021d2',
|
| 474 |
+
'\\<Longrightarrow>' : '\U000027f9',
|
| 475 |
+
'\\<leftrightarrow>' : '\U00002194',
|
| 476 |
+
'\\<longleftrightarrow>' : '\U000027f7',
|
| 477 |
+
'\\<Leftrightarrow>' : '\U000021d4',
|
| 478 |
+
'\\<Longleftrightarrow>' : '\U000027fa',
|
| 479 |
+
'\\<mapsto>' : '\U000021a6',
|
| 480 |
+
'\\<longmapsto>' : '\U000027fc',
|
| 481 |
+
'\\<midarrow>' : '\U00002500',
|
| 482 |
+
'\\<Midarrow>' : '\U00002550',
|
| 483 |
+
'\\<hookleftarrow>' : '\U000021a9',
|
| 484 |
+
'\\<hookrightarrow>' : '\U000021aa',
|
| 485 |
+
'\\<leftharpoondown>' : '\U000021bd',
|
| 486 |
+
'\\<rightharpoondown>' : '\U000021c1',
|
| 487 |
+
'\\<leftharpoonup>' : '\U000021bc',
|
| 488 |
+
'\\<rightharpoonup>' : '\U000021c0',
|
| 489 |
+
'\\<rightleftharpoons>' : '\U000021cc',
|
| 490 |
+
'\\<leadsto>' : '\U0000219d',
|
| 491 |
+
'\\<downharpoonleft>' : '\U000021c3',
|
| 492 |
+
'\\<downharpoonright>' : '\U000021c2',
|
| 493 |
+
'\\<upharpoonleft>' : '\U000021bf',
|
| 494 |
+
'\\<upharpoonright>' : '\U000021be',
|
| 495 |
+
'\\<restriction>' : '\U000021be',
|
| 496 |
+
'\\<Colon>' : '\U00002237',
|
| 497 |
+
'\\<up>' : '\U00002191',
|
| 498 |
+
'\\<Up>' : '\U000021d1',
|
| 499 |
+
'\\<down>' : '\U00002193',
|
| 500 |
+
'\\<Down>' : '\U000021d3',
|
| 501 |
+
'\\<updown>' : '\U00002195',
|
| 502 |
+
'\\<Updown>' : '\U000021d5',
|
| 503 |
+
'\\<langle>' : '\U000027e8',
|
| 504 |
+
'\\<rangle>' : '\U000027e9',
|
| 505 |
+
'\\<lceil>' : '\U00002308',
|
| 506 |
+
'\\<rceil>' : '\U00002309',
|
| 507 |
+
'\\<lfloor>' : '\U0000230a',
|
| 508 |
+
'\\<rfloor>' : '\U0000230b',
|
| 509 |
+
'\\<lparr>' : '\U00002987',
|
| 510 |
+
'\\<rparr>' : '\U00002988',
|
| 511 |
+
'\\<lbrakk>' : '\U000027e6',
|
| 512 |
+
'\\<rbrakk>' : '\U000027e7',
|
| 513 |
+
'\\<lbrace>' : '\U00002983',
|
| 514 |
+
'\\<rbrace>' : '\U00002984',
|
| 515 |
+
'\\<guillemotleft>' : '\U000000ab',
|
| 516 |
+
'\\<guillemotright>' : '\U000000bb',
|
| 517 |
+
'\\<bottom>' : '\U000022a5',
|
| 518 |
+
'\\<top>' : '\U000022a4',
|
| 519 |
+
'\\<and>' : '\U00002227',
|
| 520 |
+
'\\<And>' : '\U000022c0',
|
| 521 |
+
'\\<or>' : '\U00002228',
|
| 522 |
+
'\\<Or>' : '\U000022c1',
|
| 523 |
+
'\\<forall>' : '\U00002200',
|
| 524 |
+
'\\<exists>' : '\U00002203',
|
| 525 |
+
'\\<nexists>' : '\U00002204',
|
| 526 |
+
'\\<not>' : '\U000000ac',
|
| 527 |
+
'\\<box>' : '\U000025a1',
|
| 528 |
+
'\\<diamond>' : '\U000025c7',
|
| 529 |
+
'\\<turnstile>' : '\U000022a2',
|
| 530 |
+
'\\<Turnstile>' : '\U000022a8',
|
| 531 |
+
'\\<tturnstile>' : '\U000022a9',
|
| 532 |
+
'\\<TTurnstile>' : '\U000022ab',
|
| 533 |
+
'\\<stileturn>' : '\U000022a3',
|
| 534 |
+
'\\<surd>' : '\U0000221a',
|
| 535 |
+
'\\<le>' : '\U00002264',
|
| 536 |
+
'\\<ge>' : '\U00002265',
|
| 537 |
+
'\\<lless>' : '\U0000226a',
|
| 538 |
+
'\\<ggreater>' : '\U0000226b',
|
| 539 |
+
'\\<lesssim>' : '\U00002272',
|
| 540 |
+
'\\<greatersim>' : '\U00002273',
|
| 541 |
+
'\\<lessapprox>' : '\U00002a85',
|
| 542 |
+
'\\<greaterapprox>' : '\U00002a86',
|
| 543 |
+
'\\<in>' : '\U00002208',
|
| 544 |
+
'\\<notin>' : '\U00002209',
|
| 545 |
+
'\\<subset>' : '\U00002282',
|
| 546 |
+
'\\<supset>' : '\U00002283',
|
| 547 |
+
'\\<subseteq>' : '\U00002286',
|
| 548 |
+
'\\<supseteq>' : '\U00002287',
|
| 549 |
+
'\\<sqsubset>' : '\U0000228f',
|
| 550 |
+
'\\<sqsupset>' : '\U00002290',
|
| 551 |
+
'\\<sqsubseteq>' : '\U00002291',
|
| 552 |
+
'\\<sqsupseteq>' : '\U00002292',
|
| 553 |
+
'\\<inter>' : '\U00002229',
|
| 554 |
+
'\\<Inter>' : '\U000022c2',
|
| 555 |
+
'\\<union>' : '\U0000222a',
|
| 556 |
+
'\\<Union>' : '\U000022c3',
|
| 557 |
+
'\\<squnion>' : '\U00002294',
|
| 558 |
+
'\\<Squnion>' : '\U00002a06',
|
| 559 |
+
'\\<sqinter>' : '\U00002293',
|
| 560 |
+
'\\<Sqinter>' : '\U00002a05',
|
| 561 |
+
'\\<setminus>' : '\U00002216',
|
| 562 |
+
'\\<propto>' : '\U0000221d',
|
| 563 |
+
'\\<uplus>' : '\U0000228e',
|
| 564 |
+
'\\<Uplus>' : '\U00002a04',
|
| 565 |
+
'\\<noteq>' : '\U00002260',
|
| 566 |
+
'\\<sim>' : '\U0000223c',
|
| 567 |
+
'\\<doteq>' : '\U00002250',
|
| 568 |
+
'\\<simeq>' : '\U00002243',
|
| 569 |
+
'\\<approx>' : '\U00002248',
|
| 570 |
+
'\\<asymp>' : '\U0000224d',
|
| 571 |
+
'\\<cong>' : '\U00002245',
|
| 572 |
+
'\\<smile>' : '\U00002323',
|
| 573 |
+
'\\<equiv>' : '\U00002261',
|
| 574 |
+
'\\<frown>' : '\U00002322',
|
| 575 |
+
'\\<Join>' : '\U000022c8',
|
| 576 |
+
'\\<bowtie>' : '\U00002a1d',
|
| 577 |
+
'\\<prec>' : '\U0000227a',
|
| 578 |
+
'\\<succ>' : '\U0000227b',
|
| 579 |
+
'\\<preceq>' : '\U0000227c',
|
| 580 |
+
'\\<succeq>' : '\U0000227d',
|
| 581 |
+
'\\<parallel>' : '\U00002225',
|
| 582 |
+
'\\<bar>' : '\U000000a6',
|
| 583 |
+
'\\<plusminus>' : '\U000000b1',
|
| 584 |
+
'\\<minusplus>' : '\U00002213',
|
| 585 |
+
'\\<times>' : '\U000000d7',
|
| 586 |
+
'\\<div>' : '\U000000f7',
|
| 587 |
+
'\\<cdot>' : '\U000022c5',
|
| 588 |
+
'\\<star>' : '\U000022c6',
|
| 589 |
+
'\\<bullet>' : '\U00002219',
|
| 590 |
+
'\\<circ>' : '\U00002218',
|
| 591 |
+
'\\<dagger>' : '\U00002020',
|
| 592 |
+
'\\<ddagger>' : '\U00002021',
|
| 593 |
+
'\\<lhd>' : '\U000022b2',
|
| 594 |
+
'\\<rhd>' : '\U000022b3',
|
| 595 |
+
'\\<unlhd>' : '\U000022b4',
|
| 596 |
+
'\\<unrhd>' : '\U000022b5',
|
| 597 |
+
'\\<triangleleft>' : '\U000025c3',
|
| 598 |
+
'\\<triangleright>' : '\U000025b9',
|
| 599 |
+
'\\<triangle>' : '\U000025b3',
|
| 600 |
+
'\\<triangleq>' : '\U0000225c',
|
| 601 |
+
'\\<oplus>' : '\U00002295',
|
| 602 |
+
'\\<Oplus>' : '\U00002a01',
|
| 603 |
+
'\\<otimes>' : '\U00002297',
|
| 604 |
+
'\\<Otimes>' : '\U00002a02',
|
| 605 |
+
'\\<odot>' : '\U00002299',
|
| 606 |
+
'\\<Odot>' : '\U00002a00',
|
| 607 |
+
'\\<ominus>' : '\U00002296',
|
| 608 |
+
'\\<oslash>' : '\U00002298',
|
| 609 |
+
'\\<dots>' : '\U00002026',
|
| 610 |
+
'\\<cdots>' : '\U000022ef',
|
| 611 |
+
'\\<Sum>' : '\U00002211',
|
| 612 |
+
'\\<Prod>' : '\U0000220f',
|
| 613 |
+
'\\<Coprod>' : '\U00002210',
|
| 614 |
+
'\\<infinity>' : '\U0000221e',
|
| 615 |
+
'\\<integral>' : '\U0000222b',
|
| 616 |
+
'\\<ointegral>' : '\U0000222e',
|
| 617 |
+
'\\<clubsuit>' : '\U00002663',
|
| 618 |
+
'\\<diamondsuit>' : '\U00002662',
|
| 619 |
+
'\\<heartsuit>' : '\U00002661',
|
| 620 |
+
'\\<spadesuit>' : '\U00002660',
|
| 621 |
+
'\\<aleph>' : '\U00002135',
|
| 622 |
+
'\\<emptyset>' : '\U00002205',
|
| 623 |
+
'\\<nabla>' : '\U00002207',
|
| 624 |
+
'\\<partial>' : '\U00002202',
|
| 625 |
+
'\\<flat>' : '\U0000266d',
|
| 626 |
+
'\\<natural>' : '\U0000266e',
|
| 627 |
+
'\\<sharp>' : '\U0000266f',
|
| 628 |
+
'\\<angle>' : '\U00002220',
|
| 629 |
+
'\\<copyright>' : '\U000000a9',
|
| 630 |
+
'\\<registered>' : '\U000000ae',
|
| 631 |
+
'\\<hyphen>' : '\U000000ad',
|
| 632 |
+
'\\<inverse>' : '\U000000af',
|
| 633 |
+
'\\<onequarter>' : '\U000000bc',
|
| 634 |
+
'\\<onehalf>' : '\U000000bd',
|
| 635 |
+
'\\<threequarters>' : '\U000000be',
|
| 636 |
+
'\\<ordfeminine>' : '\U000000aa',
|
| 637 |
+
'\\<ordmasculine>' : '\U000000ba',
|
| 638 |
+
'\\<section>' : '\U000000a7',
|
| 639 |
+
'\\<paragraph>' : '\U000000b6',
|
| 640 |
+
'\\<exclamdown>' : '\U000000a1',
|
| 641 |
+
'\\<questiondown>' : '\U000000bf',
|
| 642 |
+
'\\<euro>' : '\U000020ac',
|
| 643 |
+
'\\<pounds>' : '\U000000a3',
|
| 644 |
+
'\\<yen>' : '\U000000a5',
|
| 645 |
+
'\\<cent>' : '\U000000a2',
|
| 646 |
+
'\\<currency>' : '\U000000a4',
|
| 647 |
+
'\\<degree>' : '\U000000b0',
|
| 648 |
+
'\\<amalg>' : '\U00002a3f',
|
| 649 |
+
'\\<mho>' : '\U00002127',
|
| 650 |
+
'\\<lozenge>' : '\U000025ca',
|
| 651 |
+
'\\<wp>' : '\U00002118',
|
| 652 |
+
'\\<wrong>' : '\U00002240',
|
| 653 |
+
'\\<struct>' : '\U000022c4',
|
| 654 |
+
'\\<acute>' : '\U000000b4',
|
| 655 |
+
'\\<index>' : '\U00000131',
|
| 656 |
+
'\\<dieresis>' : '\U000000a8',
|
| 657 |
+
'\\<cedilla>' : '\U000000b8',
|
| 658 |
+
'\\<hungarumlaut>' : '\U000002dd',
|
| 659 |
+
'\\<some>' : '\U000003f5',
|
| 660 |
+
'\\<newline>' : '\U000023ce',
|
| 661 |
+
'\\<open>' : '\U00002039',
|
| 662 |
+
'\\<close>' : '\U0000203a',
|
| 663 |
+
'\\<here>' : '\U00002302',
|
| 664 |
+
'\\<^sub>' : '\U000021e9',
|
| 665 |
+
'\\<^sup>' : '\U000021e7',
|
| 666 |
+
'\\<^bold>' : '\U00002759',
|
| 667 |
+
'\\<^bsub>' : '\U000021d8',
|
| 668 |
+
'\\<^esub>' : '\U000021d9',
|
| 669 |
+
'\\<^bsup>' : '\U000021d7',
|
| 670 |
+
'\\<^esup>' : '\U000021d6',
|
| 671 |
+
}
|
| 672 |
+
|
| 673 |
+
lang_map = {'isabelle' : isabelle_symbols, 'latex' : latex_symbols}
|
| 674 |
+
|
| 675 |
+
def __init__(self, **options):
|
| 676 |
+
Filter.__init__(self, **options)
|
| 677 |
+
lang = get_choice_opt(options, 'lang',
|
| 678 |
+
['isabelle', 'latex'], 'isabelle')
|
| 679 |
+
self.symbols = self.lang_map[lang]
|
| 680 |
+
|
| 681 |
+
def filter(self, lexer, stream):
|
| 682 |
+
for ttype, value in stream:
|
| 683 |
+
if value in self.symbols:
|
| 684 |
+
yield ttype, self.symbols[value]
|
| 685 |
+
else:
|
| 686 |
+
yield ttype, value
|
| 687 |
+
|
| 688 |
+
|
| 689 |
+
class KeywordCaseFilter(Filter):
|
| 690 |
+
"""Convert keywords to lowercase or uppercase or capitalize them.
|
| 691 |
+
|
| 692 |
+
This means first letter uppercase, rest lowercase.
|
| 693 |
+
|
| 694 |
+
This can be useful e.g. if you highlight Pascal code and want to adapt the
|
| 695 |
+
code to your styleguide.
|
| 696 |
+
|
| 697 |
+
Options accepted:
|
| 698 |
+
|
| 699 |
+
`case` : string
|
| 700 |
+
The casing to convert keywords to. Must be one of ``'lower'``,
|
| 701 |
+
``'upper'`` or ``'capitalize'``. The default is ``'lower'``.
|
| 702 |
+
"""
|
| 703 |
+
|
| 704 |
+
def __init__(self, **options):
|
| 705 |
+
Filter.__init__(self, **options)
|
| 706 |
+
case = get_choice_opt(options, 'case',
|
| 707 |
+
['lower', 'upper', 'capitalize'], 'lower')
|
| 708 |
+
self.convert = getattr(str, case)
|
| 709 |
+
|
| 710 |
+
def filter(self, lexer, stream):
|
| 711 |
+
for ttype, value in stream:
|
| 712 |
+
if ttype in Keyword:
|
| 713 |
+
yield ttype, self.convert(value)
|
| 714 |
+
else:
|
| 715 |
+
yield ttype, value
|
| 716 |
+
|
| 717 |
+
|
| 718 |
+
class NameHighlightFilter(Filter):
|
| 719 |
+
"""Highlight a normal Name (and Name.*) token with a different token type.
|
| 720 |
+
|
| 721 |
+
Example::
|
| 722 |
+
|
| 723 |
+
filter = NameHighlightFilter(
|
| 724 |
+
names=['foo', 'bar', 'baz'],
|
| 725 |
+
tokentype=Name.Function,
|
| 726 |
+
)
|
| 727 |
+
|
| 728 |
+
This would highlight the names "foo", "bar" and "baz"
|
| 729 |
+
as functions. `Name.Function` is the default token type.
|
| 730 |
+
|
| 731 |
+
Options accepted:
|
| 732 |
+
|
| 733 |
+
`names` : list of strings
|
| 734 |
+
A list of names that should be given the different token type.
|
| 735 |
+
There is no default.
|
| 736 |
+
`tokentype` : TokenType or string
|
| 737 |
+
A token type or a string containing a token type name that is
|
| 738 |
+
used for highlighting the strings in `names`. The default is
|
| 739 |
+
`Name.Function`.
|
| 740 |
+
"""
|
| 741 |
+
|
| 742 |
+
def __init__(self, **options):
|
| 743 |
+
Filter.__init__(self, **options)
|
| 744 |
+
self.names = set(get_list_opt(options, 'names', []))
|
| 745 |
+
tokentype = options.get('tokentype')
|
| 746 |
+
if tokentype:
|
| 747 |
+
self.tokentype = string_to_tokentype(tokentype)
|
| 748 |
+
else:
|
| 749 |
+
self.tokentype = Name.Function
|
| 750 |
+
|
| 751 |
+
def filter(self, lexer, stream):
|
| 752 |
+
for ttype, value in stream:
|
| 753 |
+
if ttype in Name and value in self.names:
|
| 754 |
+
yield self.tokentype, value
|
| 755 |
+
else:
|
| 756 |
+
yield ttype, value
|
| 757 |
+
|
| 758 |
+
|
| 759 |
+
class ErrorToken(Exception):
|
| 760 |
+
pass
|
| 761 |
+
|
| 762 |
+
|
| 763 |
+
class RaiseOnErrorTokenFilter(Filter):
|
| 764 |
+
"""Raise an exception when the lexer generates an error token.
|
| 765 |
+
|
| 766 |
+
Options accepted:
|
| 767 |
+
|
| 768 |
+
`excclass` : Exception class
|
| 769 |
+
The exception class to raise.
|
| 770 |
+
The default is `pygments.filters.ErrorToken`.
|
| 771 |
+
|
| 772 |
+
.. versionadded:: 0.8
|
| 773 |
+
"""
|
| 774 |
+
|
| 775 |
+
def __init__(self, **options):
|
| 776 |
+
Filter.__init__(self, **options)
|
| 777 |
+
self.exception = options.get('excclass', ErrorToken)
|
| 778 |
+
try:
|
| 779 |
+
# issubclass() will raise TypeError if first argument is not a class
|
| 780 |
+
if not issubclass(self.exception, Exception):
|
| 781 |
+
raise TypeError
|
| 782 |
+
except TypeError:
|
| 783 |
+
raise OptionError('excclass option is not an exception class')
|
| 784 |
+
|
| 785 |
+
def filter(self, lexer, stream):
|
| 786 |
+
for ttype, value in stream:
|
| 787 |
+
if ttype is Error:
|
| 788 |
+
raise self.exception(value)
|
| 789 |
+
yield ttype, value
|
| 790 |
+
|
| 791 |
+
|
| 792 |
+
class VisibleWhitespaceFilter(Filter):
|
| 793 |
+
"""Convert tabs, newlines and/or spaces to visible characters.
|
| 794 |
+
|
| 795 |
+
Options accepted:
|
| 796 |
+
|
| 797 |
+
`spaces` : string or bool
|
| 798 |
+
If this is a one-character string, spaces will be replaces by this string.
|
| 799 |
+
If it is another true value, spaces will be replaced by ``·`` (unicode
|
| 800 |
+
MIDDLE DOT). If it is a false value, spaces will not be replaced. The
|
| 801 |
+
default is ``False``.
|
| 802 |
+
`tabs` : string or bool
|
| 803 |
+
The same as for `spaces`, but the default replacement character is ``»``
|
| 804 |
+
(unicode RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK). The default value
|
| 805 |
+
is ``False``. Note: this will not work if the `tabsize` option for the
|
| 806 |
+
lexer is nonzero, as tabs will already have been expanded then.
|
| 807 |
+
`tabsize` : int
|
| 808 |
+
If tabs are to be replaced by this filter (see the `tabs` option), this
|
| 809 |
+
is the total number of characters that a tab should be expanded to.
|
| 810 |
+
The default is ``8``.
|
| 811 |
+
`newlines` : string or bool
|
| 812 |
+
The same as for `spaces`, but the default replacement character is ``¶``
|
| 813 |
+
(unicode PILCROW SIGN). The default value is ``False``.
|
| 814 |
+
`wstokentype` : bool
|
| 815 |
+
If true, give whitespace the special `Whitespace` token type. This allows
|
| 816 |
+
styling the visible whitespace differently (e.g. greyed out), but it can
|
| 817 |
+
disrupt background colors. The default is ``True``.
|
| 818 |
+
|
| 819 |
+
.. versionadded:: 0.8
|
| 820 |
+
"""
|
| 821 |
+
|
| 822 |
+
def __init__(self, **options):
|
| 823 |
+
Filter.__init__(self, **options)
|
| 824 |
+
for name, default in [('spaces', '·'),
|
| 825 |
+
('tabs', '»'),
|
| 826 |
+
('newlines', '¶')]:
|
| 827 |
+
opt = options.get(name, False)
|
| 828 |
+
if isinstance(opt, str) and len(opt) == 1:
|
| 829 |
+
setattr(self, name, opt)
|
| 830 |
+
else:
|
| 831 |
+
setattr(self, name, (opt and default or ''))
|
| 832 |
+
tabsize = get_int_opt(options, 'tabsize', 8)
|
| 833 |
+
if self.tabs:
|
| 834 |
+
self.tabs += ' ' * (tabsize - 1)
|
| 835 |
+
if self.newlines:
|
| 836 |
+
self.newlines += '\n'
|
| 837 |
+
self.wstt = get_bool_opt(options, 'wstokentype', True)
|
| 838 |
+
|
| 839 |
+
def filter(self, lexer, stream):
|
| 840 |
+
if self.wstt:
|
| 841 |
+
spaces = self.spaces or ' '
|
| 842 |
+
tabs = self.tabs or '\t'
|
| 843 |
+
newlines = self.newlines or '\n'
|
| 844 |
+
regex = re.compile(r'\s')
|
| 845 |
+
|
| 846 |
+
def replacefunc(wschar):
|
| 847 |
+
if wschar == ' ':
|
| 848 |
+
return spaces
|
| 849 |
+
elif wschar == '\t':
|
| 850 |
+
return tabs
|
| 851 |
+
elif wschar == '\n':
|
| 852 |
+
return newlines
|
| 853 |
+
return wschar
|
| 854 |
+
|
| 855 |
+
for ttype, value in stream:
|
| 856 |
+
yield from _replace_special(ttype, value, regex, Whitespace,
|
| 857 |
+
replacefunc)
|
| 858 |
+
else:
|
| 859 |
+
spaces, tabs, newlines = self.spaces, self.tabs, self.newlines
|
| 860 |
+
# simpler processing
|
| 861 |
+
for ttype, value in stream:
|
| 862 |
+
if spaces:
|
| 863 |
+
value = value.replace(' ', spaces)
|
| 864 |
+
if tabs:
|
| 865 |
+
value = value.replace('\t', tabs)
|
| 866 |
+
if newlines:
|
| 867 |
+
value = value.replace('\n', newlines)
|
| 868 |
+
yield ttype, value
|
| 869 |
+
|
| 870 |
+
|
| 871 |
+
class GobbleFilter(Filter):
|
| 872 |
+
"""Gobble source code lines (eats initial characters).
|
| 873 |
+
|
| 874 |
+
This filter drops the first ``n`` characters off every line of code. This
|
| 875 |
+
may be useful when the source code fed to the lexer is indented by a fixed
|
| 876 |
+
amount of space that isn't desired in the output.
|
| 877 |
+
|
| 878 |
+
Options accepted:
|
| 879 |
+
|
| 880 |
+
`n` : int
|
| 881 |
+
The number of characters to gobble.
|
| 882 |
+
|
| 883 |
+
.. versionadded:: 1.2
|
| 884 |
+
"""
|
| 885 |
+
def __init__(self, **options):
|
| 886 |
+
Filter.__init__(self, **options)
|
| 887 |
+
self.n = get_int_opt(options, 'n', 0)
|
| 888 |
+
|
| 889 |
+
def gobble(self, value, left):
|
| 890 |
+
if left < len(value):
|
| 891 |
+
return value[left:], 0
|
| 892 |
+
else:
|
| 893 |
+
return '', left - len(value)
|
| 894 |
+
|
| 895 |
+
def filter(self, lexer, stream):
|
| 896 |
+
n = self.n
|
| 897 |
+
left = n # How many characters left to gobble.
|
| 898 |
+
for ttype, value in stream:
|
| 899 |
+
# Remove ``left`` tokens from first line, ``n`` from all others.
|
| 900 |
+
parts = value.split('\n')
|
| 901 |
+
(parts[0], left) = self.gobble(parts[0], left)
|
| 902 |
+
for i in range(1, len(parts)):
|
| 903 |
+
(parts[i], left) = self.gobble(parts[i], n)
|
| 904 |
+
value = '\n'.join(parts)
|
| 905 |
+
|
| 906 |
+
if value != '':
|
| 907 |
+
yield ttype, value
|
| 908 |
+
|
| 909 |
+
|
| 910 |
+
class TokenMergeFilter(Filter):
|
| 911 |
+
"""Merge consecutive tokens with the same token type in the output stream.
|
| 912 |
+
|
| 913 |
+
.. versionadded:: 1.2
|
| 914 |
+
"""
|
| 915 |
+
def __init__(self, **options):
|
| 916 |
+
Filter.__init__(self, **options)
|
| 917 |
+
|
| 918 |
+
def filter(self, lexer, stream):
|
| 919 |
+
current_type = None
|
| 920 |
+
current_value = None
|
| 921 |
+
for ttype, value in stream:
|
| 922 |
+
if ttype is current_type:
|
| 923 |
+
current_value += value
|
| 924 |
+
else:
|
| 925 |
+
if current_type is not None:
|
| 926 |
+
yield current_type, current_value
|
| 927 |
+
current_type = ttype
|
| 928 |
+
current_value = value
|
| 929 |
+
if current_type is not None:
|
| 930 |
+
yield current_type, current_value
|
| 931 |
+
|
| 932 |
+
|
| 933 |
+
FILTERS = {
|
| 934 |
+
'codetagify': CodeTagFilter,
|
| 935 |
+
'keywordcase': KeywordCaseFilter,
|
| 936 |
+
'highlight': NameHighlightFilter,
|
| 937 |
+
'raiseonerror': RaiseOnErrorTokenFilter,
|
| 938 |
+
'whitespace': VisibleWhitespaceFilter,
|
| 939 |
+
'gobble': GobbleFilter,
|
| 940 |
+
'tokenmerge': TokenMergeFilter,
|
| 941 |
+
'symbols': SymbolFilter,
|
| 942 |
+
}
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/formatter.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.formatter
|
| 3 |
+
~~~~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Base formatter class.
|
| 6 |
+
|
| 7 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 8 |
+
:license: BSD, see LICENSE for details.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import codecs
|
| 12 |
+
|
| 13 |
+
from pip._vendor.pygments.util import get_bool_opt
|
| 14 |
+
from pip._vendor.pygments.styles import get_style_by_name
|
| 15 |
+
|
| 16 |
+
__all__ = ['Formatter']
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def _lookup_style(style):
|
| 20 |
+
if isinstance(style, str):
|
| 21 |
+
return get_style_by_name(style)
|
| 22 |
+
return style
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class Formatter:
|
| 26 |
+
"""
|
| 27 |
+
Converts a token stream to text.
|
| 28 |
+
|
| 29 |
+
Formatters should have attributes to help selecting them. These
|
| 30 |
+
are similar to the corresponding :class:`~pygments.lexer.Lexer`
|
| 31 |
+
attributes.
|
| 32 |
+
|
| 33 |
+
.. autoattribute:: name
|
| 34 |
+
:no-value:
|
| 35 |
+
|
| 36 |
+
.. autoattribute:: aliases
|
| 37 |
+
:no-value:
|
| 38 |
+
|
| 39 |
+
.. autoattribute:: filenames
|
| 40 |
+
:no-value:
|
| 41 |
+
|
| 42 |
+
You can pass options as keyword arguments to the constructor.
|
| 43 |
+
All formatters accept these basic options:
|
| 44 |
+
|
| 45 |
+
``style``
|
| 46 |
+
The style to use, can be a string or a Style subclass
|
| 47 |
+
(default: "default"). Not used by e.g. the
|
| 48 |
+
TerminalFormatter.
|
| 49 |
+
``full``
|
| 50 |
+
Tells the formatter to output a "full" document, i.e.
|
| 51 |
+
a complete self-contained document. This doesn't have
|
| 52 |
+
any effect for some formatters (default: false).
|
| 53 |
+
``title``
|
| 54 |
+
If ``full`` is true, the title that should be used to
|
| 55 |
+
caption the document (default: '').
|
| 56 |
+
``encoding``
|
| 57 |
+
If given, must be an encoding name. This will be used to
|
| 58 |
+
convert the Unicode token strings to byte strings in the
|
| 59 |
+
output. If it is "" or None, Unicode strings will be written
|
| 60 |
+
to the output file, which most file-like objects do not
|
| 61 |
+
support (default: None).
|
| 62 |
+
``outencoding``
|
| 63 |
+
Overrides ``encoding`` if given.
|
| 64 |
+
|
| 65 |
+
"""
|
| 66 |
+
|
| 67 |
+
#: Full name for the formatter, in human-readable form.
|
| 68 |
+
name = None
|
| 69 |
+
|
| 70 |
+
#: A list of short, unique identifiers that can be used to lookup
|
| 71 |
+
#: the formatter from a list, e.g. using :func:`.get_formatter_by_name()`.
|
| 72 |
+
aliases = []
|
| 73 |
+
|
| 74 |
+
#: A list of fnmatch patterns that match filenames for which this
|
| 75 |
+
#: formatter can produce output. The patterns in this list should be unique
|
| 76 |
+
#: among all formatters.
|
| 77 |
+
filenames = []
|
| 78 |
+
|
| 79 |
+
#: If True, this formatter outputs Unicode strings when no encoding
|
| 80 |
+
#: option is given.
|
| 81 |
+
unicodeoutput = True
|
| 82 |
+
|
| 83 |
+
def __init__(self, **options):
|
| 84 |
+
"""
|
| 85 |
+
As with lexers, this constructor takes arbitrary optional arguments,
|
| 86 |
+
and if you override it, you should first process your own options, then
|
| 87 |
+
call the base class implementation.
|
| 88 |
+
"""
|
| 89 |
+
self.style = _lookup_style(options.get('style', 'default'))
|
| 90 |
+
self.full = get_bool_opt(options, 'full', False)
|
| 91 |
+
self.title = options.get('title', '')
|
| 92 |
+
self.encoding = options.get('encoding', None) or None
|
| 93 |
+
if self.encoding in ('guess', 'chardet'):
|
| 94 |
+
# can happen for e.g. pygmentize -O encoding=guess
|
| 95 |
+
self.encoding = 'utf-8'
|
| 96 |
+
self.encoding = options.get('outencoding') or self.encoding
|
| 97 |
+
self.options = options
|
| 98 |
+
|
| 99 |
+
def get_style_defs(self, arg=''):
|
| 100 |
+
"""
|
| 101 |
+
This method must return statements or declarations suitable to define
|
| 102 |
+
the current style for subsequent highlighted text (e.g. CSS classes
|
| 103 |
+
in the `HTMLFormatter`).
|
| 104 |
+
|
| 105 |
+
The optional argument `arg` can be used to modify the generation and
|
| 106 |
+
is formatter dependent (it is standardized because it can be given on
|
| 107 |
+
the command line).
|
| 108 |
+
|
| 109 |
+
This method is called by the ``-S`` :doc:`command-line option <cmdline>`,
|
| 110 |
+
the `arg` is then given by the ``-a`` option.
|
| 111 |
+
"""
|
| 112 |
+
return ''
|
| 113 |
+
|
| 114 |
+
def format(self, tokensource, outfile):
|
| 115 |
+
"""
|
| 116 |
+
This method must format the tokens from the `tokensource` iterable and
|
| 117 |
+
write the formatted version to the file object `outfile`.
|
| 118 |
+
|
| 119 |
+
Formatter options can control how exactly the tokens are converted.
|
| 120 |
+
"""
|
| 121 |
+
if self.encoding:
|
| 122 |
+
# wrap the outfile in a StreamWriter
|
| 123 |
+
outfile = codecs.lookup(self.encoding)[3](outfile)
|
| 124 |
+
return self.format_unencoded(tokensource, outfile)
|
| 125 |
+
|
| 126 |
+
# Allow writing Formatter[str] or Formatter[bytes]. That's equivalent to
|
| 127 |
+
# Formatter. This helps when using third-party type stubs from typeshed.
|
| 128 |
+
def __class_getitem__(cls, name):
|
| 129 |
+
return cls
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/formatters/__init__.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.formatters
|
| 3 |
+
~~~~~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Pygments formatters.
|
| 6 |
+
|
| 7 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 8 |
+
:license: BSD, see LICENSE for details.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import re
|
| 12 |
+
import sys
|
| 13 |
+
import types
|
| 14 |
+
import fnmatch
|
| 15 |
+
from os.path import basename
|
| 16 |
+
|
| 17 |
+
from pip._vendor.pygments.formatters._mapping import FORMATTERS
|
| 18 |
+
from pip._vendor.pygments.plugin import find_plugin_formatters
|
| 19 |
+
from pip._vendor.pygments.util import ClassNotFound
|
| 20 |
+
|
| 21 |
+
__all__ = ['get_formatter_by_name', 'get_formatter_for_filename',
|
| 22 |
+
'get_all_formatters', 'load_formatter_from_file'] + list(FORMATTERS)
|
| 23 |
+
|
| 24 |
+
_formatter_cache = {} # classes by name
|
| 25 |
+
_pattern_cache = {}
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def _fn_matches(fn, glob):
|
| 29 |
+
"""Return whether the supplied file name fn matches pattern filename."""
|
| 30 |
+
if glob not in _pattern_cache:
|
| 31 |
+
pattern = _pattern_cache[glob] = re.compile(fnmatch.translate(glob))
|
| 32 |
+
return pattern.match(fn)
|
| 33 |
+
return _pattern_cache[glob].match(fn)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def _load_formatters(module_name):
|
| 37 |
+
"""Load a formatter (and all others in the module too)."""
|
| 38 |
+
mod = __import__(module_name, None, None, ['__all__'])
|
| 39 |
+
for formatter_name in mod.__all__:
|
| 40 |
+
cls = getattr(mod, formatter_name)
|
| 41 |
+
_formatter_cache[cls.name] = cls
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def get_all_formatters():
|
| 45 |
+
"""Return a generator for all formatter classes."""
|
| 46 |
+
# NB: this returns formatter classes, not info like get_all_lexers().
|
| 47 |
+
for info in FORMATTERS.values():
|
| 48 |
+
if info[1] not in _formatter_cache:
|
| 49 |
+
_load_formatters(info[0])
|
| 50 |
+
yield _formatter_cache[info[1]]
|
| 51 |
+
for _, formatter in find_plugin_formatters():
|
| 52 |
+
yield formatter
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def find_formatter_class(alias):
|
| 56 |
+
"""Lookup a formatter by alias.
|
| 57 |
+
|
| 58 |
+
Returns None if not found.
|
| 59 |
+
"""
|
| 60 |
+
for module_name, name, aliases, _, _ in FORMATTERS.values():
|
| 61 |
+
if alias in aliases:
|
| 62 |
+
if name not in _formatter_cache:
|
| 63 |
+
_load_formatters(module_name)
|
| 64 |
+
return _formatter_cache[name]
|
| 65 |
+
for _, cls in find_plugin_formatters():
|
| 66 |
+
if alias in cls.aliases:
|
| 67 |
+
return cls
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def get_formatter_by_name(_alias, **options):
|
| 71 |
+
"""
|
| 72 |
+
Return an instance of a :class:`.Formatter` subclass that has `alias` in its
|
| 73 |
+
aliases list. The formatter is given the `options` at its instantiation.
|
| 74 |
+
|
| 75 |
+
Will raise :exc:`pygments.util.ClassNotFound` if no formatter with that
|
| 76 |
+
alias is found.
|
| 77 |
+
"""
|
| 78 |
+
cls = find_formatter_class(_alias)
|
| 79 |
+
if cls is None:
|
| 80 |
+
raise ClassNotFound(f"no formatter found for name {_alias!r}")
|
| 81 |
+
return cls(**options)
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def load_formatter_from_file(filename, formattername="CustomFormatter", **options):
|
| 85 |
+
"""
|
| 86 |
+
Return a `Formatter` subclass instance loaded from the provided file, relative
|
| 87 |
+
to the current directory.
|
| 88 |
+
|
| 89 |
+
The file is expected to contain a Formatter class named ``formattername``
|
| 90 |
+
(by default, CustomFormatter). Users should be very careful with the input, because
|
| 91 |
+
this method is equivalent to running ``eval()`` on the input file. The formatter is
|
| 92 |
+
given the `options` at its instantiation.
|
| 93 |
+
|
| 94 |
+
:exc:`pygments.util.ClassNotFound` is raised if there are any errors loading
|
| 95 |
+
the formatter.
|
| 96 |
+
|
| 97 |
+
.. versionadded:: 2.2
|
| 98 |
+
"""
|
| 99 |
+
try:
|
| 100 |
+
# This empty dict will contain the namespace for the exec'd file
|
| 101 |
+
custom_namespace = {}
|
| 102 |
+
with open(filename, 'rb') as f:
|
| 103 |
+
exec(f.read(), custom_namespace)
|
| 104 |
+
# Retrieve the class `formattername` from that namespace
|
| 105 |
+
if formattername not in custom_namespace:
|
| 106 |
+
raise ClassNotFound(f'no valid {formattername} class found in {filename}')
|
| 107 |
+
formatter_class = custom_namespace[formattername]
|
| 108 |
+
# And finally instantiate it with the options
|
| 109 |
+
return formatter_class(**options)
|
| 110 |
+
except OSError as err:
|
| 111 |
+
raise ClassNotFound(f'cannot read {filename}: {err}')
|
| 112 |
+
except ClassNotFound:
|
| 113 |
+
raise
|
| 114 |
+
except Exception as err:
|
| 115 |
+
raise ClassNotFound(f'error when loading custom formatter: {err}')
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def get_formatter_for_filename(fn, **options):
|
| 119 |
+
"""
|
| 120 |
+
Return a :class:`.Formatter` subclass instance that has a filename pattern
|
| 121 |
+
matching `fn`. The formatter is given the `options` at its instantiation.
|
| 122 |
+
|
| 123 |
+
Will raise :exc:`pygments.util.ClassNotFound` if no formatter for that filename
|
| 124 |
+
is found.
|
| 125 |
+
"""
|
| 126 |
+
fn = basename(fn)
|
| 127 |
+
for modname, name, _, filenames, _ in FORMATTERS.values():
|
| 128 |
+
for filename in filenames:
|
| 129 |
+
if _fn_matches(fn, filename):
|
| 130 |
+
if name not in _formatter_cache:
|
| 131 |
+
_load_formatters(modname)
|
| 132 |
+
return _formatter_cache[name](**options)
|
| 133 |
+
for _name, cls in find_plugin_formatters():
|
| 134 |
+
for filename in cls.filenames:
|
| 135 |
+
if _fn_matches(fn, filename):
|
| 136 |
+
return cls(**options)
|
| 137 |
+
raise ClassNotFound(f"no formatter found for file name {fn!r}")
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
class _automodule(types.ModuleType):
|
| 141 |
+
"""Automatically import formatters."""
|
| 142 |
+
|
| 143 |
+
def __getattr__(self, name):
|
| 144 |
+
info = FORMATTERS.get(name)
|
| 145 |
+
if info:
|
| 146 |
+
_load_formatters(info[0])
|
| 147 |
+
cls = _formatter_cache[info[1]]
|
| 148 |
+
setattr(self, name, cls)
|
| 149 |
+
return cls
|
| 150 |
+
raise AttributeError(name)
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
oldmod = sys.modules[__name__]
|
| 154 |
+
newmod = _automodule(__name__)
|
| 155 |
+
newmod.__dict__.update(oldmod.__dict__)
|
| 156 |
+
sys.modules[__name__] = newmod
|
| 157 |
+
del newmod.newmod, newmod.oldmod, newmod.sys, newmod.types
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/formatters/_mapping.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Automatically generated by scripts/gen_mapfiles.py.
|
| 2 |
+
# DO NOT EDIT BY HAND; run `tox -e mapfiles` instead.
|
| 3 |
+
|
| 4 |
+
FORMATTERS = {
|
| 5 |
+
'BBCodeFormatter': ('pygments.formatters.bbcode', 'BBCode', ('bbcode', 'bb'), (), 'Format tokens with BBcodes. These formatting codes are used by many bulletin boards, so you can highlight your sourcecode with pygments before posting it there.'),
|
| 6 |
+
'BmpImageFormatter': ('pygments.formatters.img', 'img_bmp', ('bmp', 'bitmap'), ('*.bmp',), 'Create a bitmap image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'),
|
| 7 |
+
'GifImageFormatter': ('pygments.formatters.img', 'img_gif', ('gif',), ('*.gif',), 'Create a GIF image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'),
|
| 8 |
+
'GroffFormatter': ('pygments.formatters.groff', 'groff', ('groff', 'troff', 'roff'), (), 'Format tokens with groff escapes to change their color and font style.'),
|
| 9 |
+
'HtmlFormatter': ('pygments.formatters.html', 'HTML', ('html',), ('*.html', '*.htm'), "Format tokens as HTML 4 ``<span>`` tags. By default, the content is enclosed in a ``<pre>`` tag, itself wrapped in a ``<div>`` tag (but see the `nowrap` option). The ``<div>``'s CSS class can be set by the `cssclass` option."),
|
| 10 |
+
'IRCFormatter': ('pygments.formatters.irc', 'IRC', ('irc', 'IRC'), (), 'Format tokens with IRC color sequences'),
|
| 11 |
+
'ImageFormatter': ('pygments.formatters.img', 'img', ('img', 'IMG', 'png'), ('*.png',), 'Create a PNG image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'),
|
| 12 |
+
'JpgImageFormatter': ('pygments.formatters.img', 'img_jpg', ('jpg', 'jpeg'), ('*.jpg',), 'Create a JPEG image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'),
|
| 13 |
+
'LatexFormatter': ('pygments.formatters.latex', 'LaTeX', ('latex', 'tex'), ('*.tex',), 'Format tokens as LaTeX code. This needs the `fancyvrb` and `color` standard packages.'),
|
| 14 |
+
'NullFormatter': ('pygments.formatters.other', 'Text only', ('text', 'null'), ('*.txt',), 'Output the text unchanged without any formatting.'),
|
| 15 |
+
'PangoMarkupFormatter': ('pygments.formatters.pangomarkup', 'Pango Markup', ('pango', 'pangomarkup'), (), 'Format tokens as Pango Markup code. It can then be rendered to an SVG.'),
|
| 16 |
+
'RawTokenFormatter': ('pygments.formatters.other', 'Raw tokens', ('raw', 'tokens'), ('*.raw',), 'Format tokens as a raw representation for storing token streams.'),
|
| 17 |
+
'RtfFormatter': ('pygments.formatters.rtf', 'RTF', ('rtf',), ('*.rtf',), 'Format tokens as RTF markup. This formatter automatically outputs full RTF documents with color information and other useful stuff. Perfect for Copy and Paste into Microsoft(R) Word(R) documents.'),
|
| 18 |
+
'SvgFormatter': ('pygments.formatters.svg', 'SVG', ('svg',), ('*.svg',), 'Format tokens as an SVG graphics file. This formatter is still experimental. Each line of code is a ``<text>`` element with explicit ``x`` and ``y`` coordinates containing ``<tspan>`` elements with the individual token styles.'),
|
| 19 |
+
'Terminal256Formatter': ('pygments.formatters.terminal256', 'Terminal256', ('terminal256', 'console256', '256'), (), 'Format tokens with ANSI color sequences, for output in a 256-color terminal or console. Like in `TerminalFormatter` color sequences are terminated at newlines, so that paging the output works correctly.'),
|
| 20 |
+
'TerminalFormatter': ('pygments.formatters.terminal', 'Terminal', ('terminal', 'console'), (), 'Format tokens with ANSI color sequences, for output in a text console. Color sequences are terminated at newlines, so that paging the output works correctly.'),
|
| 21 |
+
'TerminalTrueColorFormatter': ('pygments.formatters.terminal256', 'TerminalTrueColor', ('terminal16m', 'console16m', '16m'), (), 'Format tokens with ANSI color sequences, for output in a true-color terminal or console. Like in `TerminalFormatter` color sequences are terminated at newlines, so that paging the output works correctly.'),
|
| 22 |
+
'TestcaseFormatter': ('pygments.formatters.other', 'Testcase', ('testcase',), (), 'Format tokens as appropriate for a new testcase.'),
|
| 23 |
+
}
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/lexer.py
ADDED
|
@@ -0,0 +1,965 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.lexer
|
| 3 |
+
~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Base lexer classes.
|
| 6 |
+
|
| 7 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 8 |
+
:license: BSD, see LICENSE for details.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import re
|
| 12 |
+
import sys
|
| 13 |
+
import time
|
| 14 |
+
|
| 15 |
+
from pip._vendor.pygments.filter import apply_filters, Filter
|
| 16 |
+
from pip._vendor.pygments.filters import get_filter_by_name
|
| 17 |
+
from pip._vendor.pygments.token import Error, Text, Other, Whitespace, _TokenType
|
| 18 |
+
from pip._vendor.pygments.util import get_bool_opt, get_int_opt, get_list_opt, \
|
| 19 |
+
make_analysator, Future, guess_decode
|
| 20 |
+
from pip._vendor.pygments.regexopt import regex_opt
|
| 21 |
+
|
| 22 |
+
__all__ = ['Lexer', 'RegexLexer', 'ExtendedRegexLexer', 'DelegatingLexer',
|
| 23 |
+
'LexerContext', 'include', 'inherit', 'bygroups', 'using', 'this',
|
| 24 |
+
'default', 'words', 'line_re']
|
| 25 |
+
|
| 26 |
+
line_re = re.compile('.*?\n')
|
| 27 |
+
|
| 28 |
+
_encoding_map = [(b'\xef\xbb\xbf', 'utf-8'),
|
| 29 |
+
(b'\xff\xfe\0\0', 'utf-32'),
|
| 30 |
+
(b'\0\0\xfe\xff', 'utf-32be'),
|
| 31 |
+
(b'\xff\xfe', 'utf-16'),
|
| 32 |
+
(b'\xfe\xff', 'utf-16be')]
|
| 33 |
+
|
| 34 |
+
_default_analyse = staticmethod(lambda x: 0.0)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class LexerMeta(type):
|
| 38 |
+
"""
|
| 39 |
+
This metaclass automagically converts ``analyse_text`` methods into
|
| 40 |
+
static methods which always return float values.
|
| 41 |
+
"""
|
| 42 |
+
|
| 43 |
+
def __new__(mcs, name, bases, d):
|
| 44 |
+
if 'analyse_text' in d:
|
| 45 |
+
d['analyse_text'] = make_analysator(d['analyse_text'])
|
| 46 |
+
return type.__new__(mcs, name, bases, d)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
class Lexer(metaclass=LexerMeta):
|
| 50 |
+
"""
|
| 51 |
+
Lexer for a specific language.
|
| 52 |
+
|
| 53 |
+
See also :doc:`lexerdevelopment`, a high-level guide to writing
|
| 54 |
+
lexers.
|
| 55 |
+
|
| 56 |
+
Lexer classes have attributes used for choosing the most appropriate
|
| 57 |
+
lexer based on various criteria.
|
| 58 |
+
|
| 59 |
+
.. autoattribute:: name
|
| 60 |
+
:no-value:
|
| 61 |
+
.. autoattribute:: aliases
|
| 62 |
+
:no-value:
|
| 63 |
+
.. autoattribute:: filenames
|
| 64 |
+
:no-value:
|
| 65 |
+
.. autoattribute:: alias_filenames
|
| 66 |
+
.. autoattribute:: mimetypes
|
| 67 |
+
:no-value:
|
| 68 |
+
.. autoattribute:: priority
|
| 69 |
+
|
| 70 |
+
Lexers included in Pygments should have two additional attributes:
|
| 71 |
+
|
| 72 |
+
.. autoattribute:: url
|
| 73 |
+
:no-value:
|
| 74 |
+
.. autoattribute:: version_added
|
| 75 |
+
:no-value:
|
| 76 |
+
|
| 77 |
+
Lexers included in Pygments may have additional attributes:
|
| 78 |
+
|
| 79 |
+
.. autoattribute:: _example
|
| 80 |
+
:no-value:
|
| 81 |
+
|
| 82 |
+
You can pass options to the constructor. The basic options recognized
|
| 83 |
+
by all lexers and processed by the base `Lexer` class are:
|
| 84 |
+
|
| 85 |
+
``stripnl``
|
| 86 |
+
Strip leading and trailing newlines from the input (default: True).
|
| 87 |
+
``stripall``
|
| 88 |
+
Strip all leading and trailing whitespace from the input
|
| 89 |
+
(default: False).
|
| 90 |
+
``ensurenl``
|
| 91 |
+
Make sure that the input ends with a newline (default: True). This
|
| 92 |
+
is required for some lexers that consume input linewise.
|
| 93 |
+
|
| 94 |
+
.. versionadded:: 1.3
|
| 95 |
+
|
| 96 |
+
``tabsize``
|
| 97 |
+
If given and greater than 0, expand tabs in the input (default: 0).
|
| 98 |
+
``encoding``
|
| 99 |
+
If given, must be an encoding name. This encoding will be used to
|
| 100 |
+
convert the input string to Unicode, if it is not already a Unicode
|
| 101 |
+
string (default: ``'guess'``, which uses a simple UTF-8 / Locale /
|
| 102 |
+
Latin1 detection. Can also be ``'chardet'`` to use the chardet
|
| 103 |
+
library, if it is installed.
|
| 104 |
+
``inencoding``
|
| 105 |
+
Overrides the ``encoding`` if given.
|
| 106 |
+
"""
|
| 107 |
+
|
| 108 |
+
#: Full name of the lexer, in human-readable form
|
| 109 |
+
name = None
|
| 110 |
+
|
| 111 |
+
#: A list of short, unique identifiers that can be used to look
|
| 112 |
+
#: up the lexer from a list, e.g., using `get_lexer_by_name()`.
|
| 113 |
+
aliases = []
|
| 114 |
+
|
| 115 |
+
#: A list of `fnmatch` patterns that match filenames which contain
|
| 116 |
+
#: content for this lexer. The patterns in this list should be unique among
|
| 117 |
+
#: all lexers.
|
| 118 |
+
filenames = []
|
| 119 |
+
|
| 120 |
+
#: A list of `fnmatch` patterns that match filenames which may or may not
|
| 121 |
+
#: contain content for this lexer. This list is used by the
|
| 122 |
+
#: :func:`.guess_lexer_for_filename()` function, to determine which lexers
|
| 123 |
+
#: are then included in guessing the correct one. That means that
|
| 124 |
+
#: e.g. every lexer for HTML and a template language should include
|
| 125 |
+
#: ``\*.html`` in this list.
|
| 126 |
+
alias_filenames = []
|
| 127 |
+
|
| 128 |
+
#: A list of MIME types for content that can be lexed with this lexer.
|
| 129 |
+
mimetypes = []
|
| 130 |
+
|
| 131 |
+
#: Priority, should multiple lexers match and no content is provided
|
| 132 |
+
priority = 0
|
| 133 |
+
|
| 134 |
+
#: URL of the language specification/definition. Used in the Pygments
|
| 135 |
+
#: documentation. Set to an empty string to disable.
|
| 136 |
+
url = None
|
| 137 |
+
|
| 138 |
+
#: Version of Pygments in which the lexer was added.
|
| 139 |
+
version_added = None
|
| 140 |
+
|
| 141 |
+
#: Example file name. Relative to the ``tests/examplefiles`` directory.
|
| 142 |
+
#: This is used by the documentation generator to show an example.
|
| 143 |
+
_example = None
|
| 144 |
+
|
| 145 |
+
def __init__(self, **options):
|
| 146 |
+
"""
|
| 147 |
+
This constructor takes arbitrary options as keyword arguments.
|
| 148 |
+
Every subclass must first process its own options and then call
|
| 149 |
+
the `Lexer` constructor, since it processes the basic
|
| 150 |
+
options like `stripnl`.
|
| 151 |
+
|
| 152 |
+
An example looks like this:
|
| 153 |
+
|
| 154 |
+
.. sourcecode:: python
|
| 155 |
+
|
| 156 |
+
def __init__(self, **options):
|
| 157 |
+
self.compress = options.get('compress', '')
|
| 158 |
+
Lexer.__init__(self, **options)
|
| 159 |
+
|
| 160 |
+
As these options must all be specifiable as strings (due to the
|
| 161 |
+
command line usage), there are various utility functions
|
| 162 |
+
available to help with that, see `Utilities`_.
|
| 163 |
+
"""
|
| 164 |
+
self.options = options
|
| 165 |
+
self.stripnl = get_bool_opt(options, 'stripnl', True)
|
| 166 |
+
self.stripall = get_bool_opt(options, 'stripall', False)
|
| 167 |
+
self.ensurenl = get_bool_opt(options, 'ensurenl', True)
|
| 168 |
+
self.tabsize = get_int_opt(options, 'tabsize', 0)
|
| 169 |
+
self.encoding = options.get('encoding', 'guess')
|
| 170 |
+
self.encoding = options.get('inencoding') or self.encoding
|
| 171 |
+
self.filters = []
|
| 172 |
+
for filter_ in get_list_opt(options, 'filters', ()):
|
| 173 |
+
self.add_filter(filter_)
|
| 174 |
+
|
| 175 |
+
def __repr__(self):
|
| 176 |
+
if self.options:
|
| 177 |
+
return f'<pygments.lexers.{self.__class__.__name__} with {self.options!r}>'
|
| 178 |
+
else:
|
| 179 |
+
return f'<pygments.lexers.{self.__class__.__name__}>'
|
| 180 |
+
|
| 181 |
+
def add_filter(self, filter_, **options):
|
| 182 |
+
"""
|
| 183 |
+
Add a new stream filter to this lexer.
|
| 184 |
+
"""
|
| 185 |
+
if not isinstance(filter_, Filter):
|
| 186 |
+
filter_ = get_filter_by_name(filter_, **options)
|
| 187 |
+
self.filters.append(filter_)
|
| 188 |
+
|
| 189 |
+
def analyse_text(text):
|
| 190 |
+
"""
|
| 191 |
+
A static method which is called for lexer guessing.
|
| 192 |
+
|
| 193 |
+
It should analyse the text and return a float in the range
|
| 194 |
+
from ``0.0`` to ``1.0``. If it returns ``0.0``, the lexer
|
| 195 |
+
will not be selected as the most probable one, if it returns
|
| 196 |
+
``1.0``, it will be selected immediately. This is used by
|
| 197 |
+
`guess_lexer`.
|
| 198 |
+
|
| 199 |
+
The `LexerMeta` metaclass automatically wraps this function so
|
| 200 |
+
that it works like a static method (no ``self`` or ``cls``
|
| 201 |
+
parameter) and the return value is automatically converted to
|
| 202 |
+
`float`. If the return value is an object that is boolean `False`
|
| 203 |
+
it's the same as if the return values was ``0.0``.
|
| 204 |
+
"""
|
| 205 |
+
|
| 206 |
+
def _preprocess_lexer_input(self, text):
|
| 207 |
+
"""Apply preprocessing such as decoding the input, removing BOM and normalizing newlines."""
|
| 208 |
+
|
| 209 |
+
if not isinstance(text, str):
|
| 210 |
+
if self.encoding == 'guess':
|
| 211 |
+
text, _ = guess_decode(text)
|
| 212 |
+
elif self.encoding == 'chardet':
|
| 213 |
+
try:
|
| 214 |
+
# pip vendoring note: this code is not reachable by pip,
|
| 215 |
+
# removed import of chardet to make it clear.
|
| 216 |
+
raise ImportError('chardet is not vendored by pip')
|
| 217 |
+
except ImportError as e:
|
| 218 |
+
raise ImportError('To enable chardet encoding guessing, '
|
| 219 |
+
'please install the chardet library '
|
| 220 |
+
'from http://chardet.feedparser.org/') from e
|
| 221 |
+
# check for BOM first
|
| 222 |
+
decoded = None
|
| 223 |
+
for bom, encoding in _encoding_map:
|
| 224 |
+
if text.startswith(bom):
|
| 225 |
+
decoded = text[len(bom):].decode(encoding, 'replace')
|
| 226 |
+
break
|
| 227 |
+
# no BOM found, so use chardet
|
| 228 |
+
if decoded is None:
|
| 229 |
+
enc = chardet.detect(text[:1024]) # Guess using first 1KB
|
| 230 |
+
decoded = text.decode(enc.get('encoding') or 'utf-8',
|
| 231 |
+
'replace')
|
| 232 |
+
text = decoded
|
| 233 |
+
else:
|
| 234 |
+
text = text.decode(self.encoding)
|
| 235 |
+
if text.startswith('\ufeff'):
|
| 236 |
+
text = text[len('\ufeff'):]
|
| 237 |
+
else:
|
| 238 |
+
if text.startswith('\ufeff'):
|
| 239 |
+
text = text[len('\ufeff'):]
|
| 240 |
+
|
| 241 |
+
# text now *is* a unicode string
|
| 242 |
+
text = text.replace('\r\n', '\n')
|
| 243 |
+
text = text.replace('\r', '\n')
|
| 244 |
+
if self.stripall:
|
| 245 |
+
text = text.strip()
|
| 246 |
+
elif self.stripnl:
|
| 247 |
+
text = text.strip('\n')
|
| 248 |
+
if self.tabsize > 0:
|
| 249 |
+
text = text.expandtabs(self.tabsize)
|
| 250 |
+
if self.ensurenl and not text.endswith('\n'):
|
| 251 |
+
text += '\n'
|
| 252 |
+
|
| 253 |
+
return text
|
| 254 |
+
|
| 255 |
+
def get_tokens(self, text, unfiltered=False):
|
| 256 |
+
"""
|
| 257 |
+
This method is the basic interface of a lexer. It is called by
|
| 258 |
+
the `highlight()` function. It must process the text and return an
|
| 259 |
+
iterable of ``(tokentype, value)`` pairs from `text`.
|
| 260 |
+
|
| 261 |
+
Normally, you don't need to override this method. The default
|
| 262 |
+
implementation processes the options recognized by all lexers
|
| 263 |
+
(`stripnl`, `stripall` and so on), and then yields all tokens
|
| 264 |
+
from `get_tokens_unprocessed()`, with the ``index`` dropped.
|
| 265 |
+
|
| 266 |
+
If `unfiltered` is set to `True`, the filtering mechanism is
|
| 267 |
+
bypassed even if filters are defined.
|
| 268 |
+
"""
|
| 269 |
+
text = self._preprocess_lexer_input(text)
|
| 270 |
+
|
| 271 |
+
def streamer():
|
| 272 |
+
for _, t, v in self.get_tokens_unprocessed(text):
|
| 273 |
+
yield t, v
|
| 274 |
+
stream = streamer()
|
| 275 |
+
if not unfiltered:
|
| 276 |
+
stream = apply_filters(stream, self.filters, self)
|
| 277 |
+
return stream
|
| 278 |
+
|
| 279 |
+
def get_tokens_unprocessed(self, text):
|
| 280 |
+
"""
|
| 281 |
+
This method should process the text and return an iterable of
|
| 282 |
+
``(index, tokentype, value)`` tuples where ``index`` is the starting
|
| 283 |
+
position of the token within the input text.
|
| 284 |
+
|
| 285 |
+
It must be overridden by subclasses. It is recommended to
|
| 286 |
+
implement it as a generator to maximize effectiveness.
|
| 287 |
+
"""
|
| 288 |
+
raise NotImplementedError
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
class DelegatingLexer(Lexer):
|
| 292 |
+
"""
|
| 293 |
+
This lexer takes two lexer as arguments. A root lexer and
|
| 294 |
+
a language lexer. First everything is scanned using the language
|
| 295 |
+
lexer, afterwards all ``Other`` tokens are lexed using the root
|
| 296 |
+
lexer.
|
| 297 |
+
|
| 298 |
+
The lexers from the ``template`` lexer package use this base lexer.
|
| 299 |
+
"""
|
| 300 |
+
|
| 301 |
+
def __init__(self, _root_lexer, _language_lexer, _needle=Other, **options):
|
| 302 |
+
self.root_lexer = _root_lexer(**options)
|
| 303 |
+
self.language_lexer = _language_lexer(**options)
|
| 304 |
+
self.needle = _needle
|
| 305 |
+
Lexer.__init__(self, **options)
|
| 306 |
+
|
| 307 |
+
def get_tokens_unprocessed(self, text):
|
| 308 |
+
buffered = ''
|
| 309 |
+
insertions = []
|
| 310 |
+
lng_buffer = []
|
| 311 |
+
for i, t, v in self.language_lexer.get_tokens_unprocessed(text):
|
| 312 |
+
if t is self.needle:
|
| 313 |
+
if lng_buffer:
|
| 314 |
+
insertions.append((len(buffered), lng_buffer))
|
| 315 |
+
lng_buffer = []
|
| 316 |
+
buffered += v
|
| 317 |
+
else:
|
| 318 |
+
lng_buffer.append((i, t, v))
|
| 319 |
+
if lng_buffer:
|
| 320 |
+
insertions.append((len(buffered), lng_buffer))
|
| 321 |
+
return do_insertions(insertions,
|
| 322 |
+
self.root_lexer.get_tokens_unprocessed(buffered))
|
| 323 |
+
|
| 324 |
+
|
| 325 |
+
# ------------------------------------------------------------------------------
|
| 326 |
+
# RegexLexer and ExtendedRegexLexer
|
| 327 |
+
#
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
class include(str): # pylint: disable=invalid-name
|
| 331 |
+
"""
|
| 332 |
+
Indicates that a state should include rules from another state.
|
| 333 |
+
"""
|
| 334 |
+
pass
|
| 335 |
+
|
| 336 |
+
|
| 337 |
+
class _inherit:
|
| 338 |
+
"""
|
| 339 |
+
Indicates the a state should inherit from its superclass.
|
| 340 |
+
"""
|
| 341 |
+
def __repr__(self):
|
| 342 |
+
return 'inherit'
|
| 343 |
+
|
| 344 |
+
inherit = _inherit() # pylint: disable=invalid-name
|
| 345 |
+
|
| 346 |
+
|
| 347 |
+
class combined(tuple): # pylint: disable=invalid-name
|
| 348 |
+
"""
|
| 349 |
+
Indicates a state combined from multiple states.
|
| 350 |
+
"""
|
| 351 |
+
|
| 352 |
+
def __new__(cls, *args):
|
| 353 |
+
return tuple.__new__(cls, args)
|
| 354 |
+
|
| 355 |
+
def __init__(self, *args):
|
| 356 |
+
# tuple.__init__ doesn't do anything
|
| 357 |
+
pass
|
| 358 |
+
|
| 359 |
+
|
| 360 |
+
class _PseudoMatch:
|
| 361 |
+
"""
|
| 362 |
+
A pseudo match object constructed from a string.
|
| 363 |
+
"""
|
| 364 |
+
|
| 365 |
+
def __init__(self, start, text):
|
| 366 |
+
self._text = text
|
| 367 |
+
self._start = start
|
| 368 |
+
|
| 369 |
+
def start(self, arg=None):
|
| 370 |
+
return self._start
|
| 371 |
+
|
| 372 |
+
def end(self, arg=None):
|
| 373 |
+
return self._start + len(self._text)
|
| 374 |
+
|
| 375 |
+
def group(self, arg=None):
|
| 376 |
+
if arg:
|
| 377 |
+
raise IndexError('No such group')
|
| 378 |
+
return self._text
|
| 379 |
+
|
| 380 |
+
def groups(self):
|
| 381 |
+
return (self._text,)
|
| 382 |
+
|
| 383 |
+
def groupdict(self):
|
| 384 |
+
return {}
|
| 385 |
+
|
| 386 |
+
|
| 387 |
+
def bygroups(*args):
|
| 388 |
+
"""
|
| 389 |
+
Callback that yields multiple actions for each group in the match.
|
| 390 |
+
"""
|
| 391 |
+
def callback(lexer, match, ctx=None):
|
| 392 |
+
for i, action in enumerate(args):
|
| 393 |
+
if action is None:
|
| 394 |
+
continue
|
| 395 |
+
elif type(action) is _TokenType:
|
| 396 |
+
data = match.group(i + 1)
|
| 397 |
+
if data:
|
| 398 |
+
yield match.start(i + 1), action, data
|
| 399 |
+
else:
|
| 400 |
+
data = match.group(i + 1)
|
| 401 |
+
if data is not None:
|
| 402 |
+
if ctx:
|
| 403 |
+
ctx.pos = match.start(i + 1)
|
| 404 |
+
for item in action(lexer,
|
| 405 |
+
_PseudoMatch(match.start(i + 1), data), ctx):
|
| 406 |
+
if item:
|
| 407 |
+
yield item
|
| 408 |
+
if ctx:
|
| 409 |
+
ctx.pos = match.end()
|
| 410 |
+
return callback
|
| 411 |
+
|
| 412 |
+
|
| 413 |
+
class _This:
|
| 414 |
+
"""
|
| 415 |
+
Special singleton used for indicating the caller class.
|
| 416 |
+
Used by ``using``.
|
| 417 |
+
"""
|
| 418 |
+
|
| 419 |
+
this = _This()
|
| 420 |
+
|
| 421 |
+
|
| 422 |
+
def using(_other, **kwargs):
|
| 423 |
+
"""
|
| 424 |
+
Callback that processes the match with a different lexer.
|
| 425 |
+
|
| 426 |
+
The keyword arguments are forwarded to the lexer, except `state` which
|
| 427 |
+
is handled separately.
|
| 428 |
+
|
| 429 |
+
`state` specifies the state that the new lexer will start in, and can
|
| 430 |
+
be an enumerable such as ('root', 'inline', 'string') or a simple
|
| 431 |
+
string which is assumed to be on top of the root state.
|
| 432 |
+
|
| 433 |
+
Note: For that to work, `_other` must not be an `ExtendedRegexLexer`.
|
| 434 |
+
"""
|
| 435 |
+
gt_kwargs = {}
|
| 436 |
+
if 'state' in kwargs:
|
| 437 |
+
s = kwargs.pop('state')
|
| 438 |
+
if isinstance(s, (list, tuple)):
|
| 439 |
+
gt_kwargs['stack'] = s
|
| 440 |
+
else:
|
| 441 |
+
gt_kwargs['stack'] = ('root', s)
|
| 442 |
+
|
| 443 |
+
if _other is this:
|
| 444 |
+
def callback(lexer, match, ctx=None):
|
| 445 |
+
# if keyword arguments are given the callback
|
| 446 |
+
# function has to create a new lexer instance
|
| 447 |
+
if kwargs:
|
| 448 |
+
# XXX: cache that somehow
|
| 449 |
+
d = dict(lexer.options)
|
| 450 |
+
d.update(kwargs)
|
| 451 |
+
lx = lexer.__class__(**d)
|
| 452 |
+
else:
|
| 453 |
+
lx = lexer
|
| 454 |
+
s = match.start()
|
| 455 |
+
for i, t, v in lx.get_tokens_unprocessed(match.group(), **gt_kwargs):
|
| 456 |
+
yield i + s, t, v
|
| 457 |
+
if ctx:
|
| 458 |
+
ctx.pos = match.end()
|
| 459 |
+
else:
|
| 460 |
+
def callback(lexer, match, ctx=None):
|
| 461 |
+
# XXX: cache that somehow
|
| 462 |
+
d = dict(lexer.options)
|
| 463 |
+
d.update(kwargs)
|
| 464 |
+
lx = _other(**d)
|
| 465 |
+
|
| 466 |
+
s = match.start()
|
| 467 |
+
for i, t, v in lx.get_tokens_unprocessed(match.group(), **gt_kwargs):
|
| 468 |
+
yield i + s, t, v
|
| 469 |
+
if ctx:
|
| 470 |
+
ctx.pos = match.end()
|
| 471 |
+
return callback
|
| 472 |
+
|
| 473 |
+
|
| 474 |
+
class default:
|
| 475 |
+
"""
|
| 476 |
+
Indicates a state or state action (e.g. #pop) to apply.
|
| 477 |
+
For example default('#pop') is equivalent to ('', Token, '#pop')
|
| 478 |
+
Note that state tuples may be used as well.
|
| 479 |
+
|
| 480 |
+
.. versionadded:: 2.0
|
| 481 |
+
"""
|
| 482 |
+
def __init__(self, state):
|
| 483 |
+
self.state = state
|
| 484 |
+
|
| 485 |
+
|
| 486 |
+
class words(Future):
|
| 487 |
+
"""
|
| 488 |
+
Indicates a list of literal words that is transformed into an optimized
|
| 489 |
+
regex that matches any of the words.
|
| 490 |
+
|
| 491 |
+
.. versionadded:: 2.0
|
| 492 |
+
"""
|
| 493 |
+
def __init__(self, words, prefix='', suffix=''):
|
| 494 |
+
self.words = words
|
| 495 |
+
self.prefix = prefix
|
| 496 |
+
self.suffix = suffix
|
| 497 |
+
|
| 498 |
+
def get(self):
|
| 499 |
+
return regex_opt(self.words, prefix=self.prefix, suffix=self.suffix)
|
| 500 |
+
|
| 501 |
+
|
| 502 |
+
class RegexLexerMeta(LexerMeta):
|
| 503 |
+
"""
|
| 504 |
+
Metaclass for RegexLexer, creates the self._tokens attribute from
|
| 505 |
+
self.tokens on the first instantiation.
|
| 506 |
+
"""
|
| 507 |
+
|
| 508 |
+
def _process_regex(cls, regex, rflags, state):
|
| 509 |
+
"""Preprocess the regular expression component of a token definition."""
|
| 510 |
+
if isinstance(regex, Future):
|
| 511 |
+
regex = regex.get()
|
| 512 |
+
return re.compile(regex, rflags).match
|
| 513 |
+
|
| 514 |
+
def _process_token(cls, token):
|
| 515 |
+
"""Preprocess the token component of a token definition."""
|
| 516 |
+
assert type(token) is _TokenType or callable(token), \
|
| 517 |
+
f'token type must be simple type or callable, not {token!r}'
|
| 518 |
+
return token
|
| 519 |
+
|
| 520 |
+
def _process_new_state(cls, new_state, unprocessed, processed):
|
| 521 |
+
"""Preprocess the state transition action of a token definition."""
|
| 522 |
+
if isinstance(new_state, str):
|
| 523 |
+
# an existing state
|
| 524 |
+
if new_state == '#pop':
|
| 525 |
+
return -1
|
| 526 |
+
elif new_state in unprocessed:
|
| 527 |
+
return (new_state,)
|
| 528 |
+
elif new_state == '#push':
|
| 529 |
+
return new_state
|
| 530 |
+
elif new_state[:5] == '#pop:':
|
| 531 |
+
return -int(new_state[5:])
|
| 532 |
+
else:
|
| 533 |
+
assert False, f'unknown new state {new_state!r}'
|
| 534 |
+
elif isinstance(new_state, combined):
|
| 535 |
+
# combine a new state from existing ones
|
| 536 |
+
tmp_state = '_tmp_%d' % cls._tmpname
|
| 537 |
+
cls._tmpname += 1
|
| 538 |
+
itokens = []
|
| 539 |
+
for istate in new_state:
|
| 540 |
+
assert istate != new_state, f'circular state ref {istate!r}'
|
| 541 |
+
itokens.extend(cls._process_state(unprocessed,
|
| 542 |
+
processed, istate))
|
| 543 |
+
processed[tmp_state] = itokens
|
| 544 |
+
return (tmp_state,)
|
| 545 |
+
elif isinstance(new_state, tuple):
|
| 546 |
+
# push more than one state
|
| 547 |
+
for istate in new_state:
|
| 548 |
+
assert (istate in unprocessed or
|
| 549 |
+
istate in ('#pop', '#push')), \
|
| 550 |
+
'unknown new state ' + istate
|
| 551 |
+
return new_state
|
| 552 |
+
else:
|
| 553 |
+
assert False, f'unknown new state def {new_state!r}'
|
| 554 |
+
|
| 555 |
+
def _process_state(cls, unprocessed, processed, state):
|
| 556 |
+
"""Preprocess a single state definition."""
|
| 557 |
+
assert isinstance(state, str), f"wrong state name {state!r}"
|
| 558 |
+
assert state[0] != '#', f"invalid state name {state!r}"
|
| 559 |
+
if state in processed:
|
| 560 |
+
return processed[state]
|
| 561 |
+
tokens = processed[state] = []
|
| 562 |
+
rflags = cls.flags
|
| 563 |
+
for tdef in unprocessed[state]:
|
| 564 |
+
if isinstance(tdef, include):
|
| 565 |
+
# it's a state reference
|
| 566 |
+
assert tdef != state, f"circular state reference {state!r}"
|
| 567 |
+
tokens.extend(cls._process_state(unprocessed, processed,
|
| 568 |
+
str(tdef)))
|
| 569 |
+
continue
|
| 570 |
+
if isinstance(tdef, _inherit):
|
| 571 |
+
# should be processed already, but may not in the case of:
|
| 572 |
+
# 1. the state has no counterpart in any parent
|
| 573 |
+
# 2. the state includes more than one 'inherit'
|
| 574 |
+
continue
|
| 575 |
+
if isinstance(tdef, default):
|
| 576 |
+
new_state = cls._process_new_state(tdef.state, unprocessed, processed)
|
| 577 |
+
tokens.append((re.compile('').match, None, new_state))
|
| 578 |
+
continue
|
| 579 |
+
|
| 580 |
+
assert type(tdef) is tuple, f"wrong rule def {tdef!r}"
|
| 581 |
+
|
| 582 |
+
try:
|
| 583 |
+
rex = cls._process_regex(tdef[0], rflags, state)
|
| 584 |
+
except Exception as err:
|
| 585 |
+
raise ValueError(f"uncompilable regex {tdef[0]!r} in state {state!r} of {cls!r}: {err}") from err
|
| 586 |
+
|
| 587 |
+
token = cls._process_token(tdef[1])
|
| 588 |
+
|
| 589 |
+
if len(tdef) == 2:
|
| 590 |
+
new_state = None
|
| 591 |
+
else:
|
| 592 |
+
new_state = cls._process_new_state(tdef[2],
|
| 593 |
+
unprocessed, processed)
|
| 594 |
+
|
| 595 |
+
tokens.append((rex, token, new_state))
|
| 596 |
+
return tokens
|
| 597 |
+
|
| 598 |
+
def process_tokendef(cls, name, tokendefs=None):
|
| 599 |
+
"""Preprocess a dictionary of token definitions."""
|
| 600 |
+
processed = cls._all_tokens[name] = {}
|
| 601 |
+
tokendefs = tokendefs or cls.tokens[name]
|
| 602 |
+
for state in list(tokendefs):
|
| 603 |
+
cls._process_state(tokendefs, processed, state)
|
| 604 |
+
return processed
|
| 605 |
+
|
| 606 |
+
def get_tokendefs(cls):
|
| 607 |
+
"""
|
| 608 |
+
Merge tokens from superclasses in MRO order, returning a single tokendef
|
| 609 |
+
dictionary.
|
| 610 |
+
|
| 611 |
+
Any state that is not defined by a subclass will be inherited
|
| 612 |
+
automatically. States that *are* defined by subclasses will, by
|
| 613 |
+
default, override that state in the superclass. If a subclass wishes to
|
| 614 |
+
inherit definitions from a superclass, it can use the special value
|
| 615 |
+
"inherit", which will cause the superclass' state definition to be
|
| 616 |
+
included at that point in the state.
|
| 617 |
+
"""
|
| 618 |
+
tokens = {}
|
| 619 |
+
inheritable = {}
|
| 620 |
+
for c in cls.__mro__:
|
| 621 |
+
toks = c.__dict__.get('tokens', {})
|
| 622 |
+
|
| 623 |
+
for state, items in toks.items():
|
| 624 |
+
curitems = tokens.get(state)
|
| 625 |
+
if curitems is None:
|
| 626 |
+
# N.b. because this is assigned by reference, sufficiently
|
| 627 |
+
# deep hierarchies are processed incrementally (e.g. for
|
| 628 |
+
# A(B), B(C), C(RegexLexer), B will be premodified so X(B)
|
| 629 |
+
# will not see any inherits in B).
|
| 630 |
+
tokens[state] = items
|
| 631 |
+
try:
|
| 632 |
+
inherit_ndx = items.index(inherit)
|
| 633 |
+
except ValueError:
|
| 634 |
+
continue
|
| 635 |
+
inheritable[state] = inherit_ndx
|
| 636 |
+
continue
|
| 637 |
+
|
| 638 |
+
inherit_ndx = inheritable.pop(state, None)
|
| 639 |
+
if inherit_ndx is None:
|
| 640 |
+
continue
|
| 641 |
+
|
| 642 |
+
# Replace the "inherit" value with the items
|
| 643 |
+
curitems[inherit_ndx:inherit_ndx+1] = items
|
| 644 |
+
try:
|
| 645 |
+
# N.b. this is the index in items (that is, the superclass
|
| 646 |
+
# copy), so offset required when storing below.
|
| 647 |
+
new_inh_ndx = items.index(inherit)
|
| 648 |
+
except ValueError:
|
| 649 |
+
pass
|
| 650 |
+
else:
|
| 651 |
+
inheritable[state] = inherit_ndx + new_inh_ndx
|
| 652 |
+
|
| 653 |
+
return tokens
|
| 654 |
+
|
| 655 |
+
def __call__(cls, *args, **kwds):
|
| 656 |
+
"""Instantiate cls after preprocessing its token definitions."""
|
| 657 |
+
if '_tokens' not in cls.__dict__:
|
| 658 |
+
cls._all_tokens = {}
|
| 659 |
+
cls._tmpname = 0
|
| 660 |
+
if hasattr(cls, 'token_variants') and cls.token_variants:
|
| 661 |
+
# don't process yet
|
| 662 |
+
pass
|
| 663 |
+
else:
|
| 664 |
+
cls._tokens = cls.process_tokendef('', cls.get_tokendefs())
|
| 665 |
+
|
| 666 |
+
return type.__call__(cls, *args, **kwds)
|
| 667 |
+
|
| 668 |
+
|
| 669 |
+
class RegexLexer(Lexer, metaclass=RegexLexerMeta):
|
| 670 |
+
"""
|
| 671 |
+
Base for simple stateful regular expression-based lexers.
|
| 672 |
+
Simplifies the lexing process so that you need only
|
| 673 |
+
provide a list of states and regular expressions.
|
| 674 |
+
"""
|
| 675 |
+
|
| 676 |
+
#: Flags for compiling the regular expressions.
|
| 677 |
+
#: Defaults to MULTILINE.
|
| 678 |
+
flags = re.MULTILINE
|
| 679 |
+
|
| 680 |
+
#: At all time there is a stack of states. Initially, the stack contains
|
| 681 |
+
#: a single state 'root'. The top of the stack is called "the current state".
|
| 682 |
+
#:
|
| 683 |
+
#: Dict of ``{'state': [(regex, tokentype, new_state), ...], ...}``
|
| 684 |
+
#:
|
| 685 |
+
#: ``new_state`` can be omitted to signify no state transition.
|
| 686 |
+
#: If ``new_state`` is a string, it is pushed on the stack. This ensure
|
| 687 |
+
#: the new current state is ``new_state``.
|
| 688 |
+
#: If ``new_state`` is a tuple of strings, all of those strings are pushed
|
| 689 |
+
#: on the stack and the current state will be the last element of the list.
|
| 690 |
+
#: ``new_state`` can also be ``combined('state1', 'state2', ...)``
|
| 691 |
+
#: to signify a new, anonymous state combined from the rules of two
|
| 692 |
+
#: or more existing ones.
|
| 693 |
+
#: Furthermore, it can be '#pop' to signify going back one step in
|
| 694 |
+
#: the state stack, or '#push' to push the current state on the stack
|
| 695 |
+
#: again. Note that if you push while in a combined state, the combined
|
| 696 |
+
#: state itself is pushed, and not only the state in which the rule is
|
| 697 |
+
#: defined.
|
| 698 |
+
#:
|
| 699 |
+
#: The tuple can also be replaced with ``include('state')``, in which
|
| 700 |
+
#: case the rules from the state named by the string are included in the
|
| 701 |
+
#: current one.
|
| 702 |
+
tokens = {}
|
| 703 |
+
|
| 704 |
+
def get_tokens_unprocessed(self, text, stack=('root',)):
|
| 705 |
+
"""
|
| 706 |
+
Split ``text`` into (tokentype, text) pairs.
|
| 707 |
+
|
| 708 |
+
``stack`` is the initial stack (default: ``['root']``)
|
| 709 |
+
"""
|
| 710 |
+
pos = 0
|
| 711 |
+
tokendefs = self._tokens
|
| 712 |
+
statestack = list(stack)
|
| 713 |
+
statetokens = tokendefs[statestack[-1]]
|
| 714 |
+
while 1:
|
| 715 |
+
for rexmatch, action, new_state in statetokens:
|
| 716 |
+
m = rexmatch(text, pos)
|
| 717 |
+
if m:
|
| 718 |
+
if action is not None:
|
| 719 |
+
if type(action) is _TokenType:
|
| 720 |
+
yield pos, action, m.group()
|
| 721 |
+
else:
|
| 722 |
+
yield from action(self, m)
|
| 723 |
+
pos = m.end()
|
| 724 |
+
if new_state is not None:
|
| 725 |
+
# state transition
|
| 726 |
+
if isinstance(new_state, tuple):
|
| 727 |
+
for state in new_state:
|
| 728 |
+
if state == '#pop':
|
| 729 |
+
if len(statestack) > 1:
|
| 730 |
+
statestack.pop()
|
| 731 |
+
elif state == '#push':
|
| 732 |
+
statestack.append(statestack[-1])
|
| 733 |
+
else:
|
| 734 |
+
statestack.append(state)
|
| 735 |
+
elif isinstance(new_state, int):
|
| 736 |
+
# pop, but keep at least one state on the stack
|
| 737 |
+
# (random code leading to unexpected pops should
|
| 738 |
+
# not allow exceptions)
|
| 739 |
+
if abs(new_state) >= len(statestack):
|
| 740 |
+
del statestack[1:]
|
| 741 |
+
else:
|
| 742 |
+
del statestack[new_state:]
|
| 743 |
+
elif new_state == '#push':
|
| 744 |
+
statestack.append(statestack[-1])
|
| 745 |
+
else:
|
| 746 |
+
assert False, f"wrong state def: {new_state!r}"
|
| 747 |
+
statetokens = tokendefs[statestack[-1]]
|
| 748 |
+
break
|
| 749 |
+
else:
|
| 750 |
+
# We are here only if all state tokens have been considered
|
| 751 |
+
# and there was not a match on any of them.
|
| 752 |
+
try:
|
| 753 |
+
if text[pos] == '\n':
|
| 754 |
+
# at EOL, reset state to "root"
|
| 755 |
+
statestack = ['root']
|
| 756 |
+
statetokens = tokendefs['root']
|
| 757 |
+
yield pos, Whitespace, '\n'
|
| 758 |
+
pos += 1
|
| 759 |
+
continue
|
| 760 |
+
yield pos, Error, text[pos]
|
| 761 |
+
pos += 1
|
| 762 |
+
except IndexError:
|
| 763 |
+
break
|
| 764 |
+
|
| 765 |
+
|
| 766 |
+
class LexerContext:
|
| 767 |
+
"""
|
| 768 |
+
A helper object that holds lexer position data.
|
| 769 |
+
"""
|
| 770 |
+
|
| 771 |
+
def __init__(self, text, pos, stack=None, end=None):
|
| 772 |
+
self.text = text
|
| 773 |
+
self.pos = pos
|
| 774 |
+
self.end = end or len(text) # end=0 not supported ;-)
|
| 775 |
+
self.stack = stack or ['root']
|
| 776 |
+
|
| 777 |
+
def __repr__(self):
|
| 778 |
+
return f'LexerContext({self.text!r}, {self.pos!r}, {self.stack!r})'
|
| 779 |
+
|
| 780 |
+
|
| 781 |
+
class ExtendedRegexLexer(RegexLexer):
|
| 782 |
+
"""
|
| 783 |
+
A RegexLexer that uses a context object to store its state.
|
| 784 |
+
"""
|
| 785 |
+
|
| 786 |
+
def get_tokens_unprocessed(self, text=None, context=None):
|
| 787 |
+
"""
|
| 788 |
+
Split ``text`` into (tokentype, text) pairs.
|
| 789 |
+
If ``context`` is given, use this lexer context instead.
|
| 790 |
+
"""
|
| 791 |
+
tokendefs = self._tokens
|
| 792 |
+
if not context:
|
| 793 |
+
ctx = LexerContext(text, 0)
|
| 794 |
+
statetokens = tokendefs['root']
|
| 795 |
+
else:
|
| 796 |
+
ctx = context
|
| 797 |
+
statetokens = tokendefs[ctx.stack[-1]]
|
| 798 |
+
text = ctx.text
|
| 799 |
+
while 1:
|
| 800 |
+
for rexmatch, action, new_state in statetokens:
|
| 801 |
+
m = rexmatch(text, ctx.pos, ctx.end)
|
| 802 |
+
if m:
|
| 803 |
+
if action is not None:
|
| 804 |
+
if type(action) is _TokenType:
|
| 805 |
+
yield ctx.pos, action, m.group()
|
| 806 |
+
ctx.pos = m.end()
|
| 807 |
+
else:
|
| 808 |
+
yield from action(self, m, ctx)
|
| 809 |
+
if not new_state:
|
| 810 |
+
# altered the state stack?
|
| 811 |
+
statetokens = tokendefs[ctx.stack[-1]]
|
| 812 |
+
# CAUTION: callback must set ctx.pos!
|
| 813 |
+
if new_state is not None:
|
| 814 |
+
# state transition
|
| 815 |
+
if isinstance(new_state, tuple):
|
| 816 |
+
for state in new_state:
|
| 817 |
+
if state == '#pop':
|
| 818 |
+
if len(ctx.stack) > 1:
|
| 819 |
+
ctx.stack.pop()
|
| 820 |
+
elif state == '#push':
|
| 821 |
+
ctx.stack.append(ctx.stack[-1])
|
| 822 |
+
else:
|
| 823 |
+
ctx.stack.append(state)
|
| 824 |
+
elif isinstance(new_state, int):
|
| 825 |
+
# see RegexLexer for why this check is made
|
| 826 |
+
if abs(new_state) >= len(ctx.stack):
|
| 827 |
+
del ctx.stack[1:]
|
| 828 |
+
else:
|
| 829 |
+
del ctx.stack[new_state:]
|
| 830 |
+
elif new_state == '#push':
|
| 831 |
+
ctx.stack.append(ctx.stack[-1])
|
| 832 |
+
else:
|
| 833 |
+
assert False, f"wrong state def: {new_state!r}"
|
| 834 |
+
statetokens = tokendefs[ctx.stack[-1]]
|
| 835 |
+
break
|
| 836 |
+
else:
|
| 837 |
+
try:
|
| 838 |
+
if ctx.pos >= ctx.end:
|
| 839 |
+
break
|
| 840 |
+
if text[ctx.pos] == '\n':
|
| 841 |
+
# at EOL, reset state to "root"
|
| 842 |
+
ctx.stack = ['root']
|
| 843 |
+
statetokens = tokendefs['root']
|
| 844 |
+
yield ctx.pos, Text, '\n'
|
| 845 |
+
ctx.pos += 1
|
| 846 |
+
continue
|
| 847 |
+
yield ctx.pos, Error, text[ctx.pos]
|
| 848 |
+
ctx.pos += 1
|
| 849 |
+
except IndexError:
|
| 850 |
+
break
|
| 851 |
+
|
| 852 |
+
|
| 853 |
+
def do_insertions(insertions, tokens):
|
| 854 |
+
"""
|
| 855 |
+
Helper for lexers which must combine the results of several
|
| 856 |
+
sublexers.
|
| 857 |
+
|
| 858 |
+
``insertions`` is a list of ``(index, itokens)`` pairs.
|
| 859 |
+
Each ``itokens`` iterable should be inserted at position
|
| 860 |
+
``index`` into the token stream given by the ``tokens``
|
| 861 |
+
argument.
|
| 862 |
+
|
| 863 |
+
The result is a combined token stream.
|
| 864 |
+
|
| 865 |
+
TODO: clean up the code here.
|
| 866 |
+
"""
|
| 867 |
+
insertions = iter(insertions)
|
| 868 |
+
try:
|
| 869 |
+
index, itokens = next(insertions)
|
| 870 |
+
except StopIteration:
|
| 871 |
+
# no insertions
|
| 872 |
+
yield from tokens
|
| 873 |
+
return
|
| 874 |
+
|
| 875 |
+
realpos = None
|
| 876 |
+
insleft = True
|
| 877 |
+
|
| 878 |
+
# iterate over the token stream where we want to insert
|
| 879 |
+
# the tokens from the insertion list.
|
| 880 |
+
for i, t, v in tokens:
|
| 881 |
+
# first iteration. store the position of first item
|
| 882 |
+
if realpos is None:
|
| 883 |
+
realpos = i
|
| 884 |
+
oldi = 0
|
| 885 |
+
while insleft and i + len(v) >= index:
|
| 886 |
+
tmpval = v[oldi:index - i]
|
| 887 |
+
if tmpval:
|
| 888 |
+
yield realpos, t, tmpval
|
| 889 |
+
realpos += len(tmpval)
|
| 890 |
+
for it_index, it_token, it_value in itokens:
|
| 891 |
+
yield realpos, it_token, it_value
|
| 892 |
+
realpos += len(it_value)
|
| 893 |
+
oldi = index - i
|
| 894 |
+
try:
|
| 895 |
+
index, itokens = next(insertions)
|
| 896 |
+
except StopIteration:
|
| 897 |
+
insleft = False
|
| 898 |
+
break # not strictly necessary
|
| 899 |
+
if oldi < len(v):
|
| 900 |
+
yield realpos, t, v[oldi:]
|
| 901 |
+
realpos += len(v) - oldi
|
| 902 |
+
|
| 903 |
+
# leftover tokens
|
| 904 |
+
while insleft:
|
| 905 |
+
# no normal tokens, set realpos to zero
|
| 906 |
+
realpos = realpos or 0
|
| 907 |
+
for p, t, v in itokens:
|
| 908 |
+
yield realpos, t, v
|
| 909 |
+
realpos += len(v)
|
| 910 |
+
try:
|
| 911 |
+
index, itokens = next(insertions)
|
| 912 |
+
except StopIteration:
|
| 913 |
+
insleft = False
|
| 914 |
+
break # not strictly necessary
|
| 915 |
+
|
| 916 |
+
|
| 917 |
+
class ProfilingRegexLexerMeta(RegexLexerMeta):
|
| 918 |
+
"""Metaclass for ProfilingRegexLexer, collects regex timing info."""
|
| 919 |
+
|
| 920 |
+
def _process_regex(cls, regex, rflags, state):
|
| 921 |
+
if isinstance(regex, words):
|
| 922 |
+
rex = regex_opt(regex.words, prefix=regex.prefix,
|
| 923 |
+
suffix=regex.suffix)
|
| 924 |
+
else:
|
| 925 |
+
rex = regex
|
| 926 |
+
compiled = re.compile(rex, rflags)
|
| 927 |
+
|
| 928 |
+
def match_func(text, pos, endpos=sys.maxsize):
|
| 929 |
+
info = cls._prof_data[-1].setdefault((state, rex), [0, 0.0])
|
| 930 |
+
t0 = time.time()
|
| 931 |
+
res = compiled.match(text, pos, endpos)
|
| 932 |
+
t1 = time.time()
|
| 933 |
+
info[0] += 1
|
| 934 |
+
info[1] += t1 - t0
|
| 935 |
+
return res
|
| 936 |
+
return match_func
|
| 937 |
+
|
| 938 |
+
|
| 939 |
+
class ProfilingRegexLexer(RegexLexer, metaclass=ProfilingRegexLexerMeta):
|
| 940 |
+
"""Drop-in replacement for RegexLexer that does profiling of its regexes."""
|
| 941 |
+
|
| 942 |
+
_prof_data = []
|
| 943 |
+
_prof_sort_index = 4 # defaults to time per call
|
| 944 |
+
|
| 945 |
+
def get_tokens_unprocessed(self, text, stack=('root',)):
|
| 946 |
+
# this needs to be a stack, since using(this) will produce nested calls
|
| 947 |
+
self.__class__._prof_data.append({})
|
| 948 |
+
yield from RegexLexer.get_tokens_unprocessed(self, text, stack)
|
| 949 |
+
rawdata = self.__class__._prof_data.pop()
|
| 950 |
+
data = sorted(((s, repr(r).strip('u\'').replace('\\\\', '\\')[:65],
|
| 951 |
+
n, 1000 * t, 1000 * t / n)
|
| 952 |
+
for ((s, r), (n, t)) in rawdata.items()),
|
| 953 |
+
key=lambda x: x[self._prof_sort_index],
|
| 954 |
+
reverse=True)
|
| 955 |
+
sum_total = sum(x[3] for x in data)
|
| 956 |
+
|
| 957 |
+
print()
|
| 958 |
+
print('Profiling result for %s lexing %d chars in %.3f ms' %
|
| 959 |
+
(self.__class__.__name__, len(text), sum_total))
|
| 960 |
+
print('=' * 110)
|
| 961 |
+
print('%-20s %-64s ncalls tottime percall' % ('state', 'regex'))
|
| 962 |
+
print('-' * 110)
|
| 963 |
+
for d in data:
|
| 964 |
+
print('%-20s %-65s %5d %8.4f %8.4f' % d)
|
| 965 |
+
print('=' * 110)
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/lexers/__init__.py
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.lexers
|
| 3 |
+
~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Pygments lexers.
|
| 6 |
+
|
| 7 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 8 |
+
:license: BSD, see LICENSE for details.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import re
|
| 12 |
+
import sys
|
| 13 |
+
import types
|
| 14 |
+
import fnmatch
|
| 15 |
+
from os.path import basename
|
| 16 |
+
|
| 17 |
+
from pip._vendor.pygments.lexers._mapping import LEXERS
|
| 18 |
+
from pip._vendor.pygments.modeline import get_filetype_from_buffer
|
| 19 |
+
from pip._vendor.pygments.plugin import find_plugin_lexers
|
| 20 |
+
from pip._vendor.pygments.util import ClassNotFound, guess_decode
|
| 21 |
+
|
| 22 |
+
COMPAT = {
|
| 23 |
+
'Python3Lexer': 'PythonLexer',
|
| 24 |
+
'Python3TracebackLexer': 'PythonTracebackLexer',
|
| 25 |
+
'LeanLexer': 'Lean3Lexer',
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
__all__ = ['get_lexer_by_name', 'get_lexer_for_filename', 'find_lexer_class',
|
| 29 |
+
'guess_lexer', 'load_lexer_from_file'] + list(LEXERS) + list(COMPAT)
|
| 30 |
+
|
| 31 |
+
_lexer_cache = {}
|
| 32 |
+
_pattern_cache = {}
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def _fn_matches(fn, glob):
|
| 36 |
+
"""Return whether the supplied file name fn matches pattern filename."""
|
| 37 |
+
if glob not in _pattern_cache:
|
| 38 |
+
pattern = _pattern_cache[glob] = re.compile(fnmatch.translate(glob))
|
| 39 |
+
return pattern.match(fn)
|
| 40 |
+
return _pattern_cache[glob].match(fn)
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def _load_lexers(module_name):
|
| 44 |
+
"""Load a lexer (and all others in the module too)."""
|
| 45 |
+
mod = __import__(module_name, None, None, ['__all__'])
|
| 46 |
+
for lexer_name in mod.__all__:
|
| 47 |
+
cls = getattr(mod, lexer_name)
|
| 48 |
+
_lexer_cache[cls.name] = cls
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def get_all_lexers(plugins=True):
|
| 52 |
+
"""Return a generator of tuples in the form ``(name, aliases,
|
| 53 |
+
filenames, mimetypes)`` of all know lexers.
|
| 54 |
+
|
| 55 |
+
If *plugins* is true (the default), plugin lexers supplied by entrypoints
|
| 56 |
+
are also returned. Otherwise, only builtin ones are considered.
|
| 57 |
+
"""
|
| 58 |
+
for item in LEXERS.values():
|
| 59 |
+
yield item[1:]
|
| 60 |
+
if plugins:
|
| 61 |
+
for lexer in find_plugin_lexers():
|
| 62 |
+
yield lexer.name, lexer.aliases, lexer.filenames, lexer.mimetypes
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def find_lexer_class(name):
|
| 66 |
+
"""
|
| 67 |
+
Return the `Lexer` subclass that with the *name* attribute as given by
|
| 68 |
+
the *name* argument.
|
| 69 |
+
"""
|
| 70 |
+
if name in _lexer_cache:
|
| 71 |
+
return _lexer_cache[name]
|
| 72 |
+
# lookup builtin lexers
|
| 73 |
+
for module_name, lname, aliases, _, _ in LEXERS.values():
|
| 74 |
+
if name == lname:
|
| 75 |
+
_load_lexers(module_name)
|
| 76 |
+
return _lexer_cache[name]
|
| 77 |
+
# continue with lexers from setuptools entrypoints
|
| 78 |
+
for cls in find_plugin_lexers():
|
| 79 |
+
if cls.name == name:
|
| 80 |
+
return cls
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def find_lexer_class_by_name(_alias):
|
| 84 |
+
"""
|
| 85 |
+
Return the `Lexer` subclass that has `alias` in its aliases list, without
|
| 86 |
+
instantiating it.
|
| 87 |
+
|
| 88 |
+
Like `get_lexer_by_name`, but does not instantiate the class.
|
| 89 |
+
|
| 90 |
+
Will raise :exc:`pygments.util.ClassNotFound` if no lexer with that alias is
|
| 91 |
+
found.
|
| 92 |
+
|
| 93 |
+
.. versionadded:: 2.2
|
| 94 |
+
"""
|
| 95 |
+
if not _alias:
|
| 96 |
+
raise ClassNotFound(f'no lexer for alias {_alias!r} found')
|
| 97 |
+
# lookup builtin lexers
|
| 98 |
+
for module_name, name, aliases, _, _ in LEXERS.values():
|
| 99 |
+
if _alias.lower() in aliases:
|
| 100 |
+
if name not in _lexer_cache:
|
| 101 |
+
_load_lexers(module_name)
|
| 102 |
+
return _lexer_cache[name]
|
| 103 |
+
# continue with lexers from setuptools entrypoints
|
| 104 |
+
for cls in find_plugin_lexers():
|
| 105 |
+
if _alias.lower() in cls.aliases:
|
| 106 |
+
return cls
|
| 107 |
+
raise ClassNotFound(f'no lexer for alias {_alias!r} found')
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def get_lexer_by_name(_alias, **options):
|
| 111 |
+
"""
|
| 112 |
+
Return an instance of a `Lexer` subclass that has `alias` in its
|
| 113 |
+
aliases list. The lexer is given the `options` at its
|
| 114 |
+
instantiation.
|
| 115 |
+
|
| 116 |
+
Will raise :exc:`pygments.util.ClassNotFound` if no lexer with that alias is
|
| 117 |
+
found.
|
| 118 |
+
"""
|
| 119 |
+
if not _alias:
|
| 120 |
+
raise ClassNotFound(f'no lexer for alias {_alias!r} found')
|
| 121 |
+
|
| 122 |
+
# lookup builtin lexers
|
| 123 |
+
for module_name, name, aliases, _, _ in LEXERS.values():
|
| 124 |
+
if _alias.lower() in aliases:
|
| 125 |
+
if name not in _lexer_cache:
|
| 126 |
+
_load_lexers(module_name)
|
| 127 |
+
return _lexer_cache[name](**options)
|
| 128 |
+
# continue with lexers from setuptools entrypoints
|
| 129 |
+
for cls in find_plugin_lexers():
|
| 130 |
+
if _alias.lower() in cls.aliases:
|
| 131 |
+
return cls(**options)
|
| 132 |
+
raise ClassNotFound(f'no lexer for alias {_alias!r} found')
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def load_lexer_from_file(filename, lexername="CustomLexer", **options):
|
| 136 |
+
"""Load a lexer from a file.
|
| 137 |
+
|
| 138 |
+
This method expects a file located relative to the current working
|
| 139 |
+
directory, which contains a Lexer class. By default, it expects the
|
| 140 |
+
Lexer to be name CustomLexer; you can specify your own class name
|
| 141 |
+
as the second argument to this function.
|
| 142 |
+
|
| 143 |
+
Users should be very careful with the input, because this method
|
| 144 |
+
is equivalent to running eval on the input file.
|
| 145 |
+
|
| 146 |
+
Raises ClassNotFound if there are any problems importing the Lexer.
|
| 147 |
+
|
| 148 |
+
.. versionadded:: 2.2
|
| 149 |
+
"""
|
| 150 |
+
try:
|
| 151 |
+
# This empty dict will contain the namespace for the exec'd file
|
| 152 |
+
custom_namespace = {}
|
| 153 |
+
with open(filename, 'rb') as f:
|
| 154 |
+
exec(f.read(), custom_namespace)
|
| 155 |
+
# Retrieve the class `lexername` from that namespace
|
| 156 |
+
if lexername not in custom_namespace:
|
| 157 |
+
raise ClassNotFound(f'no valid {lexername} class found in {filename}')
|
| 158 |
+
lexer_class = custom_namespace[lexername]
|
| 159 |
+
# And finally instantiate it with the options
|
| 160 |
+
return lexer_class(**options)
|
| 161 |
+
except OSError as err:
|
| 162 |
+
raise ClassNotFound(f'cannot read {filename}: {err}')
|
| 163 |
+
except ClassNotFound:
|
| 164 |
+
raise
|
| 165 |
+
except Exception as err:
|
| 166 |
+
raise ClassNotFound(f'error when loading custom lexer: {err}')
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
def find_lexer_class_for_filename(_fn, code=None):
|
| 170 |
+
"""Get a lexer for a filename.
|
| 171 |
+
|
| 172 |
+
If multiple lexers match the filename pattern, use ``analyse_text()`` to
|
| 173 |
+
figure out which one is more appropriate.
|
| 174 |
+
|
| 175 |
+
Returns None if not found.
|
| 176 |
+
"""
|
| 177 |
+
matches = []
|
| 178 |
+
fn = basename(_fn)
|
| 179 |
+
for modname, name, _, filenames, _ in LEXERS.values():
|
| 180 |
+
for filename in filenames:
|
| 181 |
+
if _fn_matches(fn, filename):
|
| 182 |
+
if name not in _lexer_cache:
|
| 183 |
+
_load_lexers(modname)
|
| 184 |
+
matches.append((_lexer_cache[name], filename))
|
| 185 |
+
for cls in find_plugin_lexers():
|
| 186 |
+
for filename in cls.filenames:
|
| 187 |
+
if _fn_matches(fn, filename):
|
| 188 |
+
matches.append((cls, filename))
|
| 189 |
+
|
| 190 |
+
if isinstance(code, bytes):
|
| 191 |
+
# decode it, since all analyse_text functions expect unicode
|
| 192 |
+
code = guess_decode(code)
|
| 193 |
+
|
| 194 |
+
def get_rating(info):
|
| 195 |
+
cls, filename = info
|
| 196 |
+
# explicit patterns get a bonus
|
| 197 |
+
bonus = '*' not in filename and 0.5 or 0
|
| 198 |
+
# The class _always_ defines analyse_text because it's included in
|
| 199 |
+
# the Lexer class. The default implementation returns None which
|
| 200 |
+
# gets turned into 0.0. Run scripts/detect_missing_analyse_text.py
|
| 201 |
+
# to find lexers which need it overridden.
|
| 202 |
+
if code:
|
| 203 |
+
return cls.analyse_text(code) + bonus, cls.__name__
|
| 204 |
+
return cls.priority + bonus, cls.__name__
|
| 205 |
+
|
| 206 |
+
if matches:
|
| 207 |
+
matches.sort(key=get_rating)
|
| 208 |
+
# print "Possible lexers, after sort:", matches
|
| 209 |
+
return matches[-1][0]
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
def get_lexer_for_filename(_fn, code=None, **options):
|
| 213 |
+
"""Get a lexer for a filename.
|
| 214 |
+
|
| 215 |
+
Return a `Lexer` subclass instance that has a filename pattern
|
| 216 |
+
matching `fn`. The lexer is given the `options` at its
|
| 217 |
+
instantiation.
|
| 218 |
+
|
| 219 |
+
Raise :exc:`pygments.util.ClassNotFound` if no lexer for that filename
|
| 220 |
+
is found.
|
| 221 |
+
|
| 222 |
+
If multiple lexers match the filename pattern, use their ``analyse_text()``
|
| 223 |
+
methods to figure out which one is more appropriate.
|
| 224 |
+
"""
|
| 225 |
+
res = find_lexer_class_for_filename(_fn, code)
|
| 226 |
+
if not res:
|
| 227 |
+
raise ClassNotFound(f'no lexer for filename {_fn!r} found')
|
| 228 |
+
return res(**options)
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
def get_lexer_for_mimetype(_mime, **options):
|
| 232 |
+
"""
|
| 233 |
+
Return a `Lexer` subclass instance that has `mime` in its mimetype
|
| 234 |
+
list. The lexer is given the `options` at its instantiation.
|
| 235 |
+
|
| 236 |
+
Will raise :exc:`pygments.util.ClassNotFound` if not lexer for that mimetype
|
| 237 |
+
is found.
|
| 238 |
+
"""
|
| 239 |
+
for modname, name, _, _, mimetypes in LEXERS.values():
|
| 240 |
+
if _mime in mimetypes:
|
| 241 |
+
if name not in _lexer_cache:
|
| 242 |
+
_load_lexers(modname)
|
| 243 |
+
return _lexer_cache[name](**options)
|
| 244 |
+
for cls in find_plugin_lexers():
|
| 245 |
+
if _mime in cls.mimetypes:
|
| 246 |
+
return cls(**options)
|
| 247 |
+
raise ClassNotFound(f'no lexer for mimetype {_mime!r} found')
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
def _iter_lexerclasses(plugins=True):
|
| 251 |
+
"""Return an iterator over all lexer classes."""
|
| 252 |
+
for key in sorted(LEXERS):
|
| 253 |
+
module_name, name = LEXERS[key][:2]
|
| 254 |
+
if name not in _lexer_cache:
|
| 255 |
+
_load_lexers(module_name)
|
| 256 |
+
yield _lexer_cache[name]
|
| 257 |
+
if plugins:
|
| 258 |
+
yield from find_plugin_lexers()
|
| 259 |
+
|
| 260 |
+
|
| 261 |
+
def guess_lexer_for_filename(_fn, _text, **options):
|
| 262 |
+
"""
|
| 263 |
+
As :func:`guess_lexer()`, but only lexers which have a pattern in `filenames`
|
| 264 |
+
or `alias_filenames` that matches `filename` are taken into consideration.
|
| 265 |
+
|
| 266 |
+
:exc:`pygments.util.ClassNotFound` is raised if no lexer thinks it can
|
| 267 |
+
handle the content.
|
| 268 |
+
"""
|
| 269 |
+
fn = basename(_fn)
|
| 270 |
+
primary = {}
|
| 271 |
+
matching_lexers = set()
|
| 272 |
+
for lexer in _iter_lexerclasses():
|
| 273 |
+
for filename in lexer.filenames:
|
| 274 |
+
if _fn_matches(fn, filename):
|
| 275 |
+
matching_lexers.add(lexer)
|
| 276 |
+
primary[lexer] = True
|
| 277 |
+
for filename in lexer.alias_filenames:
|
| 278 |
+
if _fn_matches(fn, filename):
|
| 279 |
+
matching_lexers.add(lexer)
|
| 280 |
+
primary[lexer] = False
|
| 281 |
+
if not matching_lexers:
|
| 282 |
+
raise ClassNotFound(f'no lexer for filename {fn!r} found')
|
| 283 |
+
if len(matching_lexers) == 1:
|
| 284 |
+
return matching_lexers.pop()(**options)
|
| 285 |
+
result = []
|
| 286 |
+
for lexer in matching_lexers:
|
| 287 |
+
rv = lexer.analyse_text(_text)
|
| 288 |
+
if rv == 1.0:
|
| 289 |
+
return lexer(**options)
|
| 290 |
+
result.append((rv, lexer))
|
| 291 |
+
|
| 292 |
+
def type_sort(t):
|
| 293 |
+
# sort by:
|
| 294 |
+
# - analyse score
|
| 295 |
+
# - is primary filename pattern?
|
| 296 |
+
# - priority
|
| 297 |
+
# - last resort: class name
|
| 298 |
+
return (t[0], primary[t[1]], t[1].priority, t[1].__name__)
|
| 299 |
+
result.sort(key=type_sort)
|
| 300 |
+
|
| 301 |
+
return result[-1][1](**options)
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
def guess_lexer(_text, **options):
|
| 305 |
+
"""
|
| 306 |
+
Return a `Lexer` subclass instance that's guessed from the text in
|
| 307 |
+
`text`. For that, the :meth:`.analyse_text()` method of every known lexer
|
| 308 |
+
class is called with the text as argument, and the lexer which returned the
|
| 309 |
+
highest value will be instantiated and returned.
|
| 310 |
+
|
| 311 |
+
:exc:`pygments.util.ClassNotFound` is raised if no lexer thinks it can
|
| 312 |
+
handle the content.
|
| 313 |
+
"""
|
| 314 |
+
|
| 315 |
+
if not isinstance(_text, str):
|
| 316 |
+
inencoding = options.get('inencoding', options.get('encoding'))
|
| 317 |
+
if inencoding:
|
| 318 |
+
_text = _text.decode(inencoding or 'utf8')
|
| 319 |
+
else:
|
| 320 |
+
_text, _ = guess_decode(_text)
|
| 321 |
+
|
| 322 |
+
# try to get a vim modeline first
|
| 323 |
+
ft = get_filetype_from_buffer(_text)
|
| 324 |
+
|
| 325 |
+
if ft is not None:
|
| 326 |
+
try:
|
| 327 |
+
return get_lexer_by_name(ft, **options)
|
| 328 |
+
except ClassNotFound:
|
| 329 |
+
pass
|
| 330 |
+
|
| 331 |
+
best_lexer = [0.0, None]
|
| 332 |
+
for lexer in _iter_lexerclasses():
|
| 333 |
+
rv = lexer.analyse_text(_text)
|
| 334 |
+
if rv == 1.0:
|
| 335 |
+
return lexer(**options)
|
| 336 |
+
if rv > best_lexer[0]:
|
| 337 |
+
best_lexer[:] = (rv, lexer)
|
| 338 |
+
if not best_lexer[0] or best_lexer[1] is None:
|
| 339 |
+
raise ClassNotFound('no lexer matching the text found')
|
| 340 |
+
return best_lexer[1](**options)
|
| 341 |
+
|
| 342 |
+
|
| 343 |
+
class _automodule(types.ModuleType):
|
| 344 |
+
"""Automatically import lexers."""
|
| 345 |
+
|
| 346 |
+
def __getattr__(self, name):
|
| 347 |
+
info = LEXERS.get(name)
|
| 348 |
+
if info:
|
| 349 |
+
_load_lexers(info[0])
|
| 350 |
+
cls = _lexer_cache[info[1]]
|
| 351 |
+
setattr(self, name, cls)
|
| 352 |
+
return cls
|
| 353 |
+
if name in COMPAT:
|
| 354 |
+
return getattr(self, COMPAT[name])
|
| 355 |
+
raise AttributeError(name)
|
| 356 |
+
|
| 357 |
+
|
| 358 |
+
oldmod = sys.modules[__name__]
|
| 359 |
+
newmod = _automodule(__name__)
|
| 360 |
+
newmod.__dict__.update(oldmod.__dict__)
|
| 361 |
+
sys.modules[__name__] = newmod
|
| 362 |
+
del newmod.newmod, newmod.oldmod, newmod.sys, newmod.types
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/lexers/_mapping.py
ADDED
|
@@ -0,0 +1,603 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Automatically generated by scripts/gen_mapfiles.py.
|
| 2 |
+
# DO NOT EDIT BY HAND; run `tox -e mapfiles` instead.
|
| 3 |
+
|
| 4 |
+
LEXERS = {
|
| 5 |
+
'ABAPLexer': ('pip._vendor.pygments.lexers.business', 'ABAP', ('abap',), ('*.abap', '*.ABAP'), ('text/x-abap',)),
|
| 6 |
+
'AMDGPULexer': ('pip._vendor.pygments.lexers.amdgpu', 'AMDGPU', ('amdgpu',), ('*.isa',), ()),
|
| 7 |
+
'APLLexer': ('pip._vendor.pygments.lexers.apl', 'APL', ('apl',), ('*.apl', '*.aplf', '*.aplo', '*.apln', '*.aplc', '*.apli', '*.dyalog'), ()),
|
| 8 |
+
'AbnfLexer': ('pip._vendor.pygments.lexers.grammar_notation', 'ABNF', ('abnf',), ('*.abnf',), ('text/x-abnf',)),
|
| 9 |
+
'ActionScript3Lexer': ('pip._vendor.pygments.lexers.actionscript', 'ActionScript 3', ('actionscript3', 'as3'), ('*.as',), ('application/x-actionscript3', 'text/x-actionscript3', 'text/actionscript3')),
|
| 10 |
+
'ActionScriptLexer': ('pip._vendor.pygments.lexers.actionscript', 'ActionScript', ('actionscript', 'as'), ('*.as',), ('application/x-actionscript', 'text/x-actionscript', 'text/actionscript')),
|
| 11 |
+
'AdaLexer': ('pip._vendor.pygments.lexers.ada', 'Ada', ('ada', 'ada95', 'ada2005'), ('*.adb', '*.ads', '*.ada'), ('text/x-ada',)),
|
| 12 |
+
'AdlLexer': ('pip._vendor.pygments.lexers.archetype', 'ADL', ('adl',), ('*.adl', '*.adls', '*.adlf', '*.adlx'), ()),
|
| 13 |
+
'AgdaLexer': ('pip._vendor.pygments.lexers.haskell', 'Agda', ('agda',), ('*.agda',), ('text/x-agda',)),
|
| 14 |
+
'AheuiLexer': ('pip._vendor.pygments.lexers.esoteric', 'Aheui', ('aheui',), ('*.aheui',), ()),
|
| 15 |
+
'AlloyLexer': ('pip._vendor.pygments.lexers.dsls', 'Alloy', ('alloy',), ('*.als',), ('text/x-alloy',)),
|
| 16 |
+
'AmbientTalkLexer': ('pip._vendor.pygments.lexers.ambient', 'AmbientTalk', ('ambienttalk', 'ambienttalk/2', 'at'), ('*.at',), ('text/x-ambienttalk',)),
|
| 17 |
+
'AmplLexer': ('pip._vendor.pygments.lexers.ampl', 'Ampl', ('ampl',), ('*.run',), ()),
|
| 18 |
+
'Angular2HtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML + Angular2', ('html+ng2',), ('*.ng2',), ()),
|
| 19 |
+
'Angular2Lexer': ('pip._vendor.pygments.lexers.templates', 'Angular2', ('ng2',), (), ()),
|
| 20 |
+
'AntlrActionScriptLexer': ('pip._vendor.pygments.lexers.parsers', 'ANTLR With ActionScript Target', ('antlr-actionscript', 'antlr-as'), ('*.G', '*.g'), ()),
|
| 21 |
+
'AntlrCSharpLexer': ('pip._vendor.pygments.lexers.parsers', 'ANTLR With C# Target', ('antlr-csharp', 'antlr-c#'), ('*.G', '*.g'), ()),
|
| 22 |
+
'AntlrCppLexer': ('pip._vendor.pygments.lexers.parsers', 'ANTLR With CPP Target', ('antlr-cpp',), ('*.G', '*.g'), ()),
|
| 23 |
+
'AntlrJavaLexer': ('pip._vendor.pygments.lexers.parsers', 'ANTLR With Java Target', ('antlr-java',), ('*.G', '*.g'), ()),
|
| 24 |
+
'AntlrLexer': ('pip._vendor.pygments.lexers.parsers', 'ANTLR', ('antlr',), (), ()),
|
| 25 |
+
'AntlrObjectiveCLexer': ('pip._vendor.pygments.lexers.parsers', 'ANTLR With ObjectiveC Target', ('antlr-objc',), ('*.G', '*.g'), ()),
|
| 26 |
+
'AntlrPerlLexer': ('pip._vendor.pygments.lexers.parsers', 'ANTLR With Perl Target', ('antlr-perl',), ('*.G', '*.g'), ()),
|
| 27 |
+
'AntlrPythonLexer': ('pip._vendor.pygments.lexers.parsers', 'ANTLR With Python Target', ('antlr-python',), ('*.G', '*.g'), ()),
|
| 28 |
+
'AntlrRubyLexer': ('pip._vendor.pygments.lexers.parsers', 'ANTLR With Ruby Target', ('antlr-ruby', 'antlr-rb'), ('*.G', '*.g'), ()),
|
| 29 |
+
'ApacheConfLexer': ('pip._vendor.pygments.lexers.configs', 'ApacheConf', ('apacheconf', 'aconf', 'apache'), ('.htaccess', 'apache.conf', 'apache2.conf'), ('text/x-apacheconf',)),
|
| 30 |
+
'AppleScriptLexer': ('pip._vendor.pygments.lexers.scripting', 'AppleScript', ('applescript',), ('*.applescript',), ()),
|
| 31 |
+
'ArduinoLexer': ('pip._vendor.pygments.lexers.c_like', 'Arduino', ('arduino',), ('*.ino',), ('text/x-arduino',)),
|
| 32 |
+
'ArrowLexer': ('pip._vendor.pygments.lexers.arrow', 'Arrow', ('arrow',), ('*.arw',), ()),
|
| 33 |
+
'ArturoLexer': ('pip._vendor.pygments.lexers.arturo', 'Arturo', ('arturo', 'art'), ('*.art',), ()),
|
| 34 |
+
'AscLexer': ('pip._vendor.pygments.lexers.asc', 'ASCII armored', ('asc', 'pem'), ('*.asc', '*.pem', 'id_dsa', 'id_ecdsa', 'id_ecdsa_sk', 'id_ed25519', 'id_ed25519_sk', 'id_rsa'), ('application/pgp-keys', 'application/pgp-encrypted', 'application/pgp-signature', 'application/pem-certificate-chain')),
|
| 35 |
+
'Asn1Lexer': ('pip._vendor.pygments.lexers.asn1', 'ASN.1', ('asn1',), ('*.asn1',), ()),
|
| 36 |
+
'AspectJLexer': ('pip._vendor.pygments.lexers.jvm', 'AspectJ', ('aspectj',), ('*.aj',), ('text/x-aspectj',)),
|
| 37 |
+
'AsymptoteLexer': ('pip._vendor.pygments.lexers.graphics', 'Asymptote', ('asymptote', 'asy'), ('*.asy',), ('text/x-asymptote',)),
|
| 38 |
+
'AugeasLexer': ('pip._vendor.pygments.lexers.configs', 'Augeas', ('augeas',), ('*.aug',), ()),
|
| 39 |
+
'AutoItLexer': ('pip._vendor.pygments.lexers.automation', 'AutoIt', ('autoit',), ('*.au3',), ('text/x-autoit',)),
|
| 40 |
+
'AutohotkeyLexer': ('pip._vendor.pygments.lexers.automation', 'autohotkey', ('autohotkey', 'ahk'), ('*.ahk', '*.ahkl'), ('text/x-autohotkey',)),
|
| 41 |
+
'AwkLexer': ('pip._vendor.pygments.lexers.textedit', 'Awk', ('awk', 'gawk', 'mawk', 'nawk'), ('*.awk',), ('application/x-awk',)),
|
| 42 |
+
'BBCBasicLexer': ('pip._vendor.pygments.lexers.basic', 'BBC Basic', ('bbcbasic',), ('*.bbc',), ()),
|
| 43 |
+
'BBCodeLexer': ('pip._vendor.pygments.lexers.markup', 'BBCode', ('bbcode',), (), ('text/x-bbcode',)),
|
| 44 |
+
'BCLexer': ('pip._vendor.pygments.lexers.algebra', 'BC', ('bc',), ('*.bc',), ()),
|
| 45 |
+
'BQNLexer': ('pip._vendor.pygments.lexers.bqn', 'BQN', ('bqn',), ('*.bqn',), ()),
|
| 46 |
+
'BSTLexer': ('pip._vendor.pygments.lexers.bibtex', 'BST', ('bst', 'bst-pybtex'), ('*.bst',), ()),
|
| 47 |
+
'BareLexer': ('pip._vendor.pygments.lexers.bare', 'BARE', ('bare',), ('*.bare',), ()),
|
| 48 |
+
'BaseMakefileLexer': ('pip._vendor.pygments.lexers.make', 'Base Makefile', ('basemake',), (), ()),
|
| 49 |
+
'BashLexer': ('pip._vendor.pygments.lexers.shell', 'Bash', ('bash', 'sh', 'ksh', 'zsh', 'shell', 'openrc'), ('*.sh', '*.ksh', '*.bash', '*.ebuild', '*.eclass', '*.exheres-0', '*.exlib', '*.zsh', '.bashrc', 'bashrc', '.bash_*', 'bash_*', 'zshrc', '.zshrc', '.kshrc', 'kshrc', 'PKGBUILD'), ('application/x-sh', 'application/x-shellscript', 'text/x-shellscript')),
|
| 50 |
+
'BashSessionLexer': ('pip._vendor.pygments.lexers.shell', 'Bash Session', ('console', 'shell-session'), ('*.sh-session', '*.shell-session'), ('application/x-shell-session', 'application/x-sh-session')),
|
| 51 |
+
'BatchLexer': ('pip._vendor.pygments.lexers.shell', 'Batchfile', ('batch', 'bat', 'dosbatch', 'winbatch'), ('*.bat', '*.cmd'), ('application/x-dos-batch',)),
|
| 52 |
+
'BddLexer': ('pip._vendor.pygments.lexers.bdd', 'Bdd', ('bdd',), ('*.feature',), ('text/x-bdd',)),
|
| 53 |
+
'BefungeLexer': ('pip._vendor.pygments.lexers.esoteric', 'Befunge', ('befunge',), ('*.befunge',), ('application/x-befunge',)),
|
| 54 |
+
'BerryLexer': ('pip._vendor.pygments.lexers.berry', 'Berry', ('berry', 'be'), ('*.be',), ('text/x-berry', 'application/x-berry')),
|
| 55 |
+
'BibTeXLexer': ('pip._vendor.pygments.lexers.bibtex', 'BibTeX', ('bibtex', 'bib'), ('*.bib',), ('text/x-bibtex',)),
|
| 56 |
+
'BlitzBasicLexer': ('pip._vendor.pygments.lexers.basic', 'BlitzBasic', ('blitzbasic', 'b3d', 'bplus'), ('*.bb', '*.decls'), ('text/x-bb',)),
|
| 57 |
+
'BlitzMaxLexer': ('pip._vendor.pygments.lexers.basic', 'BlitzMax', ('blitzmax', 'bmax'), ('*.bmx',), ('text/x-bmx',)),
|
| 58 |
+
'BlueprintLexer': ('pip._vendor.pygments.lexers.blueprint', 'Blueprint', ('blueprint',), ('*.blp',), ('text/x-blueprint',)),
|
| 59 |
+
'BnfLexer': ('pip._vendor.pygments.lexers.grammar_notation', 'BNF', ('bnf',), ('*.bnf',), ('text/x-bnf',)),
|
| 60 |
+
'BoaLexer': ('pip._vendor.pygments.lexers.boa', 'Boa', ('boa',), ('*.boa',), ()),
|
| 61 |
+
'BooLexer': ('pip._vendor.pygments.lexers.dotnet', 'Boo', ('boo',), ('*.boo',), ('text/x-boo',)),
|
| 62 |
+
'BoogieLexer': ('pip._vendor.pygments.lexers.verification', 'Boogie', ('boogie',), ('*.bpl',), ()),
|
| 63 |
+
'BrainfuckLexer': ('pip._vendor.pygments.lexers.esoteric', 'Brainfuck', ('brainfuck', 'bf'), ('*.bf', '*.b'), ('application/x-brainfuck',)),
|
| 64 |
+
'BugsLexer': ('pip._vendor.pygments.lexers.modeling', 'BUGS', ('bugs', 'winbugs', 'openbugs'), ('*.bug',), ()),
|
| 65 |
+
'CAmkESLexer': ('pip._vendor.pygments.lexers.esoteric', 'CAmkES', ('camkes', 'idl4'), ('*.camkes', '*.idl4'), ()),
|
| 66 |
+
'CLexer': ('pip._vendor.pygments.lexers.c_cpp', 'C', ('c',), ('*.c', '*.h', '*.idc', '*.x[bp]m'), ('text/x-chdr', 'text/x-csrc', 'image/x-xbitmap', 'image/x-xpixmap')),
|
| 67 |
+
'CMakeLexer': ('pip._vendor.pygments.lexers.make', 'CMake', ('cmake',), ('*.cmake', 'CMakeLists.txt'), ('text/x-cmake',)),
|
| 68 |
+
'CObjdumpLexer': ('pip._vendor.pygments.lexers.asm', 'c-objdump', ('c-objdump',), ('*.c-objdump',), ('text/x-c-objdump',)),
|
| 69 |
+
'CPSALexer': ('pip._vendor.pygments.lexers.lisp', 'CPSA', ('cpsa',), ('*.cpsa',), ()),
|
| 70 |
+
'CSSUL4Lexer': ('pip._vendor.pygments.lexers.ul4', 'CSS+UL4', ('css+ul4',), ('*.cssul4',), ()),
|
| 71 |
+
'CSharpAspxLexer': ('pip._vendor.pygments.lexers.dotnet', 'aspx-cs', ('aspx-cs',), ('*.aspx', '*.asax', '*.ascx', '*.ashx', '*.asmx', '*.axd'), ()),
|
| 72 |
+
'CSharpLexer': ('pip._vendor.pygments.lexers.dotnet', 'C#', ('csharp', 'c#', 'cs'), ('*.cs',), ('text/x-csharp',)),
|
| 73 |
+
'Ca65Lexer': ('pip._vendor.pygments.lexers.asm', 'ca65 assembler', ('ca65',), ('*.s',), ()),
|
| 74 |
+
'CadlLexer': ('pip._vendor.pygments.lexers.archetype', 'cADL', ('cadl',), ('*.cadl',), ()),
|
| 75 |
+
'CapDLLexer': ('pip._vendor.pygments.lexers.esoteric', 'CapDL', ('capdl',), ('*.cdl',), ()),
|
| 76 |
+
'CapnProtoLexer': ('pip._vendor.pygments.lexers.capnproto', "Cap'n Proto", ('capnp',), ('*.capnp',), ()),
|
| 77 |
+
'CarbonLexer': ('pip._vendor.pygments.lexers.carbon', 'Carbon', ('carbon',), ('*.carbon',), ('text/x-carbon',)),
|
| 78 |
+
'CbmBasicV2Lexer': ('pip._vendor.pygments.lexers.basic', 'CBM BASIC V2', ('cbmbas',), ('*.bas',), ()),
|
| 79 |
+
'CddlLexer': ('pip._vendor.pygments.lexers.cddl', 'CDDL', ('cddl',), ('*.cddl',), ('text/x-cddl',)),
|
| 80 |
+
'CeylonLexer': ('pip._vendor.pygments.lexers.jvm', 'Ceylon', ('ceylon',), ('*.ceylon',), ('text/x-ceylon',)),
|
| 81 |
+
'Cfengine3Lexer': ('pip._vendor.pygments.lexers.configs', 'CFEngine3', ('cfengine3', 'cf3'), ('*.cf',), ()),
|
| 82 |
+
'ChaiscriptLexer': ('pip._vendor.pygments.lexers.scripting', 'ChaiScript', ('chaiscript', 'chai'), ('*.chai',), ('text/x-chaiscript', 'application/x-chaiscript')),
|
| 83 |
+
'ChapelLexer': ('pip._vendor.pygments.lexers.chapel', 'Chapel', ('chapel', 'chpl'), ('*.chpl',), ()),
|
| 84 |
+
'CharmciLexer': ('pip._vendor.pygments.lexers.c_like', 'Charmci', ('charmci',), ('*.ci',), ()),
|
| 85 |
+
'CheetahHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Cheetah', ('html+cheetah', 'html+spitfire', 'htmlcheetah'), (), ('text/html+cheetah', 'text/html+spitfire')),
|
| 86 |
+
'CheetahJavascriptLexer': ('pip._vendor.pygments.lexers.templates', 'JavaScript+Cheetah', ('javascript+cheetah', 'js+cheetah', 'javascript+spitfire', 'js+spitfire'), (), ('application/x-javascript+cheetah', 'text/x-javascript+cheetah', 'text/javascript+cheetah', 'application/x-javascript+spitfire', 'text/x-javascript+spitfire', 'text/javascript+spitfire')),
|
| 87 |
+
'CheetahLexer': ('pip._vendor.pygments.lexers.templates', 'Cheetah', ('cheetah', 'spitfire'), ('*.tmpl', '*.spt'), ('application/x-cheetah', 'application/x-spitfire')),
|
| 88 |
+
'CheetahXmlLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Cheetah', ('xml+cheetah', 'xml+spitfire'), (), ('application/xml+cheetah', 'application/xml+spitfire')),
|
| 89 |
+
'CirruLexer': ('pip._vendor.pygments.lexers.webmisc', 'Cirru', ('cirru',), ('*.cirru',), ('text/x-cirru',)),
|
| 90 |
+
'ClayLexer': ('pip._vendor.pygments.lexers.c_like', 'Clay', ('clay',), ('*.clay',), ('text/x-clay',)),
|
| 91 |
+
'CleanLexer': ('pip._vendor.pygments.lexers.clean', 'Clean', ('clean',), ('*.icl', '*.dcl'), ()),
|
| 92 |
+
'ClojureLexer': ('pip._vendor.pygments.lexers.jvm', 'Clojure', ('clojure', 'clj'), ('*.clj', '*.cljc'), ('text/x-clojure', 'application/x-clojure')),
|
| 93 |
+
'ClojureScriptLexer': ('pip._vendor.pygments.lexers.jvm', 'ClojureScript', ('clojurescript', 'cljs'), ('*.cljs',), ('text/x-clojurescript', 'application/x-clojurescript')),
|
| 94 |
+
'CobolFreeformatLexer': ('pip._vendor.pygments.lexers.business', 'COBOLFree', ('cobolfree',), ('*.cbl', '*.CBL'), ()),
|
| 95 |
+
'CobolLexer': ('pip._vendor.pygments.lexers.business', 'COBOL', ('cobol',), ('*.cob', '*.COB', '*.cpy', '*.CPY'), ('text/x-cobol',)),
|
| 96 |
+
'CodeQLLexer': ('pip._vendor.pygments.lexers.codeql', 'CodeQL', ('codeql', 'ql'), ('*.ql', '*.qll'), ()),
|
| 97 |
+
'CoffeeScriptLexer': ('pip._vendor.pygments.lexers.javascript', 'CoffeeScript', ('coffeescript', 'coffee-script', 'coffee'), ('*.coffee',), ('text/coffeescript',)),
|
| 98 |
+
'ColdfusionCFCLexer': ('pip._vendor.pygments.lexers.templates', 'Coldfusion CFC', ('cfc',), ('*.cfc',), ()),
|
| 99 |
+
'ColdfusionHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'Coldfusion HTML', ('cfm',), ('*.cfm', '*.cfml'), ('application/x-coldfusion',)),
|
| 100 |
+
'ColdfusionLexer': ('pip._vendor.pygments.lexers.templates', 'cfstatement', ('cfs',), (), ()),
|
| 101 |
+
'Comal80Lexer': ('pip._vendor.pygments.lexers.comal', 'COMAL-80', ('comal', 'comal80'), ('*.cml', '*.comal'), ()),
|
| 102 |
+
'CommonLispLexer': ('pip._vendor.pygments.lexers.lisp', 'Common Lisp', ('common-lisp', 'cl', 'lisp'), ('*.cl', '*.lisp'), ('text/x-common-lisp',)),
|
| 103 |
+
'ComponentPascalLexer': ('pip._vendor.pygments.lexers.oberon', 'Component Pascal', ('componentpascal', 'cp'), ('*.cp', '*.cps'), ('text/x-component-pascal',)),
|
| 104 |
+
'CplintLexer': ('pip._vendor.pygments.lexers.cplint', 'cplint', ('cplint',), ('*.ecl', '*.prolog', '*.pro', '*.pl', '*.P', '*.lpad', '*.cpl'), ('text/x-cplint',)),
|
| 105 |
+
'CppLexer': ('pip._vendor.pygments.lexers.c_cpp', 'C++', ('cpp', 'c++'), ('*.cpp', '*.hpp', '*.c++', '*.h++', '*.cc', '*.hh', '*.cxx', '*.hxx', '*.C', '*.H', '*.cp', '*.CPP', '*.tpp', '*.cppm', '*.ixx', '*.mxx'), ('text/x-c++hdr', 'text/x-c++src')),
|
| 106 |
+
'CppObjdumpLexer': ('pip._vendor.pygments.lexers.asm', 'cpp-objdump', ('cpp-objdump', 'c++-objdumb', 'cxx-objdump'), ('*.cpp-objdump', '*.c++-objdump', '*.cxx-objdump'), ('text/x-cpp-objdump',)),
|
| 107 |
+
'CrmshLexer': ('pip._vendor.pygments.lexers.dsls', 'Crmsh', ('crmsh', 'pcmk'), ('*.crmsh', '*.pcmk'), ()),
|
| 108 |
+
'CrocLexer': ('pip._vendor.pygments.lexers.d', 'Croc', ('croc',), ('*.croc',), ('text/x-crocsrc',)),
|
| 109 |
+
'CryptolLexer': ('pip._vendor.pygments.lexers.haskell', 'Cryptol', ('cryptol', 'cry'), ('*.cry',), ('text/x-cryptol',)),
|
| 110 |
+
'CrystalLexer': ('pip._vendor.pygments.lexers.crystal', 'Crystal', ('cr', 'crystal'), ('*.cr',), ('text/x-crystal',)),
|
| 111 |
+
'CsoundDocumentLexer': ('pip._vendor.pygments.lexers.csound', 'Csound Document', ('csound-document', 'csound-csd'), ('*.csd',), ()),
|
| 112 |
+
'CsoundOrchestraLexer': ('pip._vendor.pygments.lexers.csound', 'Csound Orchestra', ('csound', 'csound-orc'), ('*.orc', '*.udo'), ()),
|
| 113 |
+
'CsoundScoreLexer': ('pip._vendor.pygments.lexers.csound', 'Csound Score', ('csound-score', 'csound-sco'), ('*.sco',), ()),
|
| 114 |
+
'CssDjangoLexer': ('pip._vendor.pygments.lexers.templates', 'CSS+Django/Jinja', ('css+django', 'css+jinja'), ('*.css.j2', '*.css.jinja2'), ('text/css+django', 'text/css+jinja')),
|
| 115 |
+
'CssErbLexer': ('pip._vendor.pygments.lexers.templates', 'CSS+Ruby', ('css+ruby', 'css+erb'), (), ('text/css+ruby',)),
|
| 116 |
+
'CssGenshiLexer': ('pip._vendor.pygments.lexers.templates', 'CSS+Genshi Text', ('css+genshitext', 'css+genshi'), (), ('text/css+genshi',)),
|
| 117 |
+
'CssLexer': ('pip._vendor.pygments.lexers.css', 'CSS', ('css',), ('*.css',), ('text/css',)),
|
| 118 |
+
'CssPhpLexer': ('pip._vendor.pygments.lexers.templates', 'CSS+PHP', ('css+php',), (), ('text/css+php',)),
|
| 119 |
+
'CssSmartyLexer': ('pip._vendor.pygments.lexers.templates', 'CSS+Smarty', ('css+smarty',), (), ('text/css+smarty',)),
|
| 120 |
+
'CudaLexer': ('pip._vendor.pygments.lexers.c_like', 'CUDA', ('cuda', 'cu'), ('*.cu', '*.cuh'), ('text/x-cuda',)),
|
| 121 |
+
'CypherLexer': ('pip._vendor.pygments.lexers.graph', 'Cypher', ('cypher',), ('*.cyp', '*.cypher'), ()),
|
| 122 |
+
'CythonLexer': ('pip._vendor.pygments.lexers.python', 'Cython', ('cython', 'pyx', 'pyrex'), ('*.pyx', '*.pxd', '*.pxi'), ('text/x-cython', 'application/x-cython')),
|
| 123 |
+
'DLexer': ('pip._vendor.pygments.lexers.d', 'D', ('d',), ('*.d', '*.di'), ('text/x-dsrc',)),
|
| 124 |
+
'DObjdumpLexer': ('pip._vendor.pygments.lexers.asm', 'd-objdump', ('d-objdump',), ('*.d-objdump',), ('text/x-d-objdump',)),
|
| 125 |
+
'DarcsPatchLexer': ('pip._vendor.pygments.lexers.diff', 'Darcs Patch', ('dpatch',), ('*.dpatch', '*.darcspatch'), ()),
|
| 126 |
+
'DartLexer': ('pip._vendor.pygments.lexers.javascript', 'Dart', ('dart',), ('*.dart',), ('text/x-dart',)),
|
| 127 |
+
'Dasm16Lexer': ('pip._vendor.pygments.lexers.asm', 'DASM16', ('dasm16',), ('*.dasm16', '*.dasm'), ('text/x-dasm16',)),
|
| 128 |
+
'DaxLexer': ('pip._vendor.pygments.lexers.dax', 'Dax', ('dax',), ('*.dax',), ()),
|
| 129 |
+
'DebianControlLexer': ('pip._vendor.pygments.lexers.installers', 'Debian Control file', ('debcontrol', 'control'), ('control',), ()),
|
| 130 |
+
'DebianSourcesLexer': ('pip._vendor.pygments.lexers.installers', 'Debian Sources file', ('debian.sources',), ('*.sources',), ()),
|
| 131 |
+
'DelphiLexer': ('pip._vendor.pygments.lexers.pascal', 'Delphi', ('delphi', 'pas', 'pascal', 'objectpascal'), ('*.pas', '*.dpr'), ('text/x-pascal',)),
|
| 132 |
+
'DesktopLexer': ('pip._vendor.pygments.lexers.configs', 'Desktop file', ('desktop',), ('*.desktop',), ('application/x-desktop',)),
|
| 133 |
+
'DevicetreeLexer': ('pip._vendor.pygments.lexers.devicetree', 'Devicetree', ('devicetree', 'dts'), ('*.dts', '*.dtsi'), ('text/x-c',)),
|
| 134 |
+
'DgLexer': ('pip._vendor.pygments.lexers.python', 'dg', ('dg',), ('*.dg',), ('text/x-dg',)),
|
| 135 |
+
'DiffLexer': ('pip._vendor.pygments.lexers.diff', 'Diff', ('diff', 'udiff'), ('*.diff', '*.patch'), ('text/x-diff', 'text/x-patch')),
|
| 136 |
+
'DjangoLexer': ('pip._vendor.pygments.lexers.templates', 'Django/Jinja', ('django', 'jinja'), (), ('application/x-django-templating', 'application/x-jinja')),
|
| 137 |
+
'DnsZoneLexer': ('pip._vendor.pygments.lexers.dns', 'Zone', ('zone',), ('*.zone',), ('text/dns',)),
|
| 138 |
+
'DockerLexer': ('pip._vendor.pygments.lexers.configs', 'Docker', ('docker', 'dockerfile'), ('Dockerfile', '*.docker'), ('text/x-dockerfile-config',)),
|
| 139 |
+
'DtdLexer': ('pip._vendor.pygments.lexers.html', 'DTD', ('dtd',), ('*.dtd',), ('application/xml-dtd',)),
|
| 140 |
+
'DuelLexer': ('pip._vendor.pygments.lexers.webmisc', 'Duel', ('duel', 'jbst', 'jsonml+bst'), ('*.duel', '*.jbst'), ('text/x-duel', 'text/x-jbst')),
|
| 141 |
+
'DylanConsoleLexer': ('pip._vendor.pygments.lexers.dylan', 'Dylan session', ('dylan-console', 'dylan-repl'), ('*.dylan-console',), ('text/x-dylan-console',)),
|
| 142 |
+
'DylanLexer': ('pip._vendor.pygments.lexers.dylan', 'Dylan', ('dylan',), ('*.dylan', '*.dyl', '*.intr'), ('text/x-dylan',)),
|
| 143 |
+
'DylanLidLexer': ('pip._vendor.pygments.lexers.dylan', 'DylanLID', ('dylan-lid', 'lid'), ('*.lid', '*.hdp'), ('text/x-dylan-lid',)),
|
| 144 |
+
'ECLLexer': ('pip._vendor.pygments.lexers.ecl', 'ECL', ('ecl',), ('*.ecl',), ('application/x-ecl',)),
|
| 145 |
+
'ECLexer': ('pip._vendor.pygments.lexers.c_like', 'eC', ('ec',), ('*.ec', '*.eh'), ('text/x-echdr', 'text/x-ecsrc')),
|
| 146 |
+
'EarlGreyLexer': ('pip._vendor.pygments.lexers.javascript', 'Earl Grey', ('earl-grey', 'earlgrey', 'eg'), ('*.eg',), ('text/x-earl-grey',)),
|
| 147 |
+
'EasytrieveLexer': ('pip._vendor.pygments.lexers.scripting', 'Easytrieve', ('easytrieve',), ('*.ezt', '*.mac'), ('text/x-easytrieve',)),
|
| 148 |
+
'EbnfLexer': ('pip._vendor.pygments.lexers.parsers', 'EBNF', ('ebnf',), ('*.ebnf',), ('text/x-ebnf',)),
|
| 149 |
+
'EiffelLexer': ('pip._vendor.pygments.lexers.eiffel', 'Eiffel', ('eiffel',), ('*.e',), ('text/x-eiffel',)),
|
| 150 |
+
'ElixirConsoleLexer': ('pip._vendor.pygments.lexers.erlang', 'Elixir iex session', ('iex',), (), ('text/x-elixir-shellsession',)),
|
| 151 |
+
'ElixirLexer': ('pip._vendor.pygments.lexers.erlang', 'Elixir', ('elixir', 'ex', 'exs'), ('*.ex', '*.eex', '*.exs', '*.leex'), ('text/x-elixir',)),
|
| 152 |
+
'ElmLexer': ('pip._vendor.pygments.lexers.elm', 'Elm', ('elm',), ('*.elm',), ('text/x-elm',)),
|
| 153 |
+
'ElpiLexer': ('pip._vendor.pygments.lexers.elpi', 'Elpi', ('elpi',), ('*.elpi',), ('text/x-elpi',)),
|
| 154 |
+
'EmacsLispLexer': ('pip._vendor.pygments.lexers.lisp', 'EmacsLisp', ('emacs-lisp', 'elisp', 'emacs'), ('*.el',), ('text/x-elisp', 'application/x-elisp')),
|
| 155 |
+
'EmailLexer': ('pip._vendor.pygments.lexers.email', 'E-mail', ('email', 'eml'), ('*.eml',), ('message/rfc822',)),
|
| 156 |
+
'ErbLexer': ('pip._vendor.pygments.lexers.templates', 'ERB', ('erb',), (), ('application/x-ruby-templating',)),
|
| 157 |
+
'ErlangLexer': ('pip._vendor.pygments.lexers.erlang', 'Erlang', ('erlang',), ('*.erl', '*.hrl', '*.es', '*.escript'), ('text/x-erlang',)),
|
| 158 |
+
'ErlangShellLexer': ('pip._vendor.pygments.lexers.erlang', 'Erlang erl session', ('erl',), ('*.erl-sh',), ('text/x-erl-shellsession',)),
|
| 159 |
+
'EvoqueHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Evoque', ('html+evoque',), (), ('text/html+evoque',)),
|
| 160 |
+
'EvoqueLexer': ('pip._vendor.pygments.lexers.templates', 'Evoque', ('evoque',), ('*.evoque',), ('application/x-evoque',)),
|
| 161 |
+
'EvoqueXmlLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Evoque', ('xml+evoque',), (), ('application/xml+evoque',)),
|
| 162 |
+
'ExeclineLexer': ('pip._vendor.pygments.lexers.shell', 'execline', ('execline',), ('*.exec',), ()),
|
| 163 |
+
'EzhilLexer': ('pip._vendor.pygments.lexers.ezhil', 'Ezhil', ('ezhil',), ('*.n',), ('text/x-ezhil',)),
|
| 164 |
+
'FSharpLexer': ('pip._vendor.pygments.lexers.dotnet', 'F#', ('fsharp', 'f#'), ('*.fs', '*.fsi', '*.fsx'), ('text/x-fsharp',)),
|
| 165 |
+
'FStarLexer': ('pip._vendor.pygments.lexers.ml', 'FStar', ('fstar',), ('*.fst', '*.fsti'), ('text/x-fstar',)),
|
| 166 |
+
'FactorLexer': ('pip._vendor.pygments.lexers.factor', 'Factor', ('factor',), ('*.factor',), ('text/x-factor',)),
|
| 167 |
+
'FancyLexer': ('pip._vendor.pygments.lexers.ruby', 'Fancy', ('fancy', 'fy'), ('*.fy', '*.fancypack'), ('text/x-fancysrc',)),
|
| 168 |
+
'FantomLexer': ('pip._vendor.pygments.lexers.fantom', 'Fantom', ('fan',), ('*.fan',), ('application/x-fantom',)),
|
| 169 |
+
'FelixLexer': ('pip._vendor.pygments.lexers.felix', 'Felix', ('felix', 'flx'), ('*.flx', '*.flxh'), ('text/x-felix',)),
|
| 170 |
+
'FennelLexer': ('pip._vendor.pygments.lexers.lisp', 'Fennel', ('fennel', 'fnl'), ('*.fnl', '*.fnlm'), ('text/x-fennel',)),
|
| 171 |
+
'FiftLexer': ('pip._vendor.pygments.lexers.fift', 'Fift', ('fift', 'fif'), ('*.fif',), ()),
|
| 172 |
+
'FishShellLexer': ('pip._vendor.pygments.lexers.shell', 'Fish', ('fish', 'fishshell'), ('*.fish', '*.load'), ('application/x-fish',)),
|
| 173 |
+
'FlatlineLexer': ('pip._vendor.pygments.lexers.dsls', 'Flatline', ('flatline',), (), ('text/x-flatline',)),
|
| 174 |
+
'FloScriptLexer': ('pip._vendor.pygments.lexers.floscript', 'FloScript', ('floscript', 'flo'), ('*.flo',), ()),
|
| 175 |
+
'ForthLexer': ('pip._vendor.pygments.lexers.forth', 'Forth', ('forth',), ('*.frt', '*.fs'), ('application/x-forth',)),
|
| 176 |
+
'FortranFixedLexer': ('pip._vendor.pygments.lexers.fortran', 'FortranFixed', ('fortranfixed',), ('*.f', '*.F'), ()),
|
| 177 |
+
'FortranLexer': ('pip._vendor.pygments.lexers.fortran', 'Fortran', ('fortran', 'f90'), ('*.f03', '*.f90', '*.F03', '*.F90'), ('text/x-fortran',)),
|
| 178 |
+
'FoxProLexer': ('pip._vendor.pygments.lexers.foxpro', 'FoxPro', ('foxpro', 'vfp', 'clipper', 'xbase'), ('*.PRG', '*.prg'), ()),
|
| 179 |
+
'FreeFemLexer': ('pip._vendor.pygments.lexers.freefem', 'Freefem', ('freefem',), ('*.edp',), ('text/x-freefem',)),
|
| 180 |
+
'FuncLexer': ('pip._vendor.pygments.lexers.func', 'FunC', ('func', 'fc'), ('*.fc', '*.func'), ()),
|
| 181 |
+
'FutharkLexer': ('pip._vendor.pygments.lexers.futhark', 'Futhark', ('futhark',), ('*.fut',), ('text/x-futhark',)),
|
| 182 |
+
'GAPConsoleLexer': ('pip._vendor.pygments.lexers.algebra', 'GAP session', ('gap-console', 'gap-repl'), ('*.tst',), ()),
|
| 183 |
+
'GAPLexer': ('pip._vendor.pygments.lexers.algebra', 'GAP', ('gap',), ('*.g', '*.gd', '*.gi', '*.gap'), ()),
|
| 184 |
+
'GDScriptLexer': ('pip._vendor.pygments.lexers.gdscript', 'GDScript', ('gdscript', 'gd'), ('*.gd',), ('text/x-gdscript', 'application/x-gdscript')),
|
| 185 |
+
'GLShaderLexer': ('pip._vendor.pygments.lexers.graphics', 'GLSL', ('glsl',), ('*.vert', '*.frag', '*.geo'), ('text/x-glslsrc',)),
|
| 186 |
+
'GSQLLexer': ('pip._vendor.pygments.lexers.gsql', 'GSQL', ('gsql',), ('*.gsql',), ()),
|
| 187 |
+
'GasLexer': ('pip._vendor.pygments.lexers.asm', 'GAS', ('gas', 'asm'), ('*.s', '*.S'), ('text/x-gas',)),
|
| 188 |
+
'GcodeLexer': ('pip._vendor.pygments.lexers.gcodelexer', 'g-code', ('gcode',), ('*.gcode',), ()),
|
| 189 |
+
'GenshiLexer': ('pip._vendor.pygments.lexers.templates', 'Genshi', ('genshi', 'kid', 'xml+genshi', 'xml+kid'), ('*.kid',), ('application/x-genshi', 'application/x-kid')),
|
| 190 |
+
'GenshiTextLexer': ('pip._vendor.pygments.lexers.templates', 'Genshi Text', ('genshitext',), (), ('application/x-genshi-text', 'text/x-genshi')),
|
| 191 |
+
'GettextLexer': ('pip._vendor.pygments.lexers.textfmts', 'Gettext Catalog', ('pot', 'po'), ('*.pot', '*.po'), ('application/x-gettext', 'text/x-gettext', 'text/gettext')),
|
| 192 |
+
'GherkinLexer': ('pip._vendor.pygments.lexers.testing', 'Gherkin', ('gherkin', 'cucumber'), ('*.feature',), ('text/x-gherkin',)),
|
| 193 |
+
'GleamLexer': ('pip._vendor.pygments.lexers.gleam', 'Gleam', ('gleam',), ('*.gleam',), ('text/x-gleam',)),
|
| 194 |
+
'GnuplotLexer': ('pip._vendor.pygments.lexers.graphics', 'Gnuplot', ('gnuplot',), ('*.plot', '*.plt'), ('text/x-gnuplot',)),
|
| 195 |
+
'GoLexer': ('pip._vendor.pygments.lexers.go', 'Go', ('go', 'golang'), ('*.go',), ('text/x-gosrc',)),
|
| 196 |
+
'GoloLexer': ('pip._vendor.pygments.lexers.jvm', 'Golo', ('golo',), ('*.golo',), ()),
|
| 197 |
+
'GoodDataCLLexer': ('pip._vendor.pygments.lexers.business', 'GoodData-CL', ('gooddata-cl',), ('*.gdc',), ('text/x-gooddata-cl',)),
|
| 198 |
+
'GoogleSqlLexer': ('pip._vendor.pygments.lexers.sql', 'GoogleSQL', ('googlesql', 'zetasql'), ('*.googlesql', '*.googlesql.sql'), ('text/x-google-sql', 'text/x-google-sql-aux')),
|
| 199 |
+
'GosuLexer': ('pip._vendor.pygments.lexers.jvm', 'Gosu', ('gosu',), ('*.gs', '*.gsx', '*.gsp', '*.vark'), ('text/x-gosu',)),
|
| 200 |
+
'GosuTemplateLexer': ('pip._vendor.pygments.lexers.jvm', 'Gosu Template', ('gst',), ('*.gst',), ('text/x-gosu-template',)),
|
| 201 |
+
'GraphQLLexer': ('pip._vendor.pygments.lexers.graphql', 'GraphQL', ('graphql',), ('*.graphql',), ()),
|
| 202 |
+
'GraphvizLexer': ('pip._vendor.pygments.lexers.graphviz', 'Graphviz', ('graphviz', 'dot'), ('*.gv', '*.dot'), ('text/x-graphviz', 'text/vnd.graphviz')),
|
| 203 |
+
'GroffLexer': ('pip._vendor.pygments.lexers.markup', 'Groff', ('groff', 'nroff', 'man'), ('*.[1-9]', '*.man', '*.1p', '*.3pm'), ('application/x-troff', 'text/troff')),
|
| 204 |
+
'GroovyLexer': ('pip._vendor.pygments.lexers.jvm', 'Groovy', ('groovy',), ('*.groovy', '*.gradle'), ('text/x-groovy',)),
|
| 205 |
+
'HLSLShaderLexer': ('pip._vendor.pygments.lexers.graphics', 'HLSL', ('hlsl',), ('*.hlsl', '*.hlsli'), ('text/x-hlsl',)),
|
| 206 |
+
'HTMLUL4Lexer': ('pip._vendor.pygments.lexers.ul4', 'HTML+UL4', ('html+ul4',), ('*.htmlul4',), ()),
|
| 207 |
+
'HamlLexer': ('pip._vendor.pygments.lexers.html', 'Haml', ('haml',), ('*.haml',), ('text/x-haml',)),
|
| 208 |
+
'HandlebarsHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Handlebars', ('html+handlebars',), ('*.handlebars', '*.hbs'), ('text/html+handlebars', 'text/x-handlebars-template')),
|
| 209 |
+
'HandlebarsLexer': ('pip._vendor.pygments.lexers.templates', 'Handlebars', ('handlebars',), (), ()),
|
| 210 |
+
'HareLexer': ('pip._vendor.pygments.lexers.hare', 'Hare', ('hare',), ('*.ha',), ('text/x-hare',)),
|
| 211 |
+
'HaskellLexer': ('pip._vendor.pygments.lexers.haskell', 'Haskell', ('haskell', 'hs'), ('*.hs',), ('text/x-haskell',)),
|
| 212 |
+
'HaxeLexer': ('pip._vendor.pygments.lexers.haxe', 'Haxe', ('haxe', 'hxsl', 'hx'), ('*.hx', '*.hxsl'), ('text/haxe', 'text/x-haxe', 'text/x-hx')),
|
| 213 |
+
'HexdumpLexer': ('pip._vendor.pygments.lexers.hexdump', 'Hexdump', ('hexdump',), (), ()),
|
| 214 |
+
'HsailLexer': ('pip._vendor.pygments.lexers.asm', 'HSAIL', ('hsail', 'hsa'), ('*.hsail',), ('text/x-hsail',)),
|
| 215 |
+
'HspecLexer': ('pip._vendor.pygments.lexers.haskell', 'Hspec', ('hspec',), ('*Spec.hs',), ()),
|
| 216 |
+
'HtmlDjangoLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Django/Jinja', ('html+django', 'html+jinja', 'htmldjango'), ('*.html.j2', '*.htm.j2', '*.xhtml.j2', '*.html.jinja2', '*.htm.jinja2', '*.xhtml.jinja2'), ('text/html+django', 'text/html+jinja')),
|
| 217 |
+
'HtmlGenshiLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Genshi', ('html+genshi', 'html+kid'), (), ('text/html+genshi',)),
|
| 218 |
+
'HtmlLexer': ('pip._vendor.pygments.lexers.html', 'HTML', ('html',), ('*.html', '*.htm', '*.xhtml', '*.xslt'), ('text/html', 'application/xhtml+xml')),
|
| 219 |
+
'HtmlPhpLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+PHP', ('html+php',), ('*.phtml',), ('application/x-php', 'application/x-httpd-php', 'application/x-httpd-php3', 'application/x-httpd-php4', 'application/x-httpd-php5')),
|
| 220 |
+
'HtmlSmartyLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Smarty', ('html+smarty',), (), ('text/html+smarty',)),
|
| 221 |
+
'HttpLexer': ('pip._vendor.pygments.lexers.textfmts', 'HTTP', ('http',), (), ()),
|
| 222 |
+
'HxmlLexer': ('pip._vendor.pygments.lexers.haxe', 'Hxml', ('haxeml', 'hxml'), ('*.hxml',), ()),
|
| 223 |
+
'HyLexer': ('pip._vendor.pygments.lexers.lisp', 'Hy', ('hylang', 'hy'), ('*.hy',), ('text/x-hy', 'application/x-hy')),
|
| 224 |
+
'HybrisLexer': ('pip._vendor.pygments.lexers.scripting', 'Hybris', ('hybris',), ('*.hyb',), ('text/x-hybris', 'application/x-hybris')),
|
| 225 |
+
'IDLLexer': ('pip._vendor.pygments.lexers.idl', 'IDL', ('idl',), ('*.pro',), ('text/idl',)),
|
| 226 |
+
'IconLexer': ('pip._vendor.pygments.lexers.unicon', 'Icon', ('icon',), ('*.icon', '*.ICON'), ()),
|
| 227 |
+
'IdrisLexer': ('pip._vendor.pygments.lexers.haskell', 'Idris', ('idris', 'idr'), ('*.idr',), ('text/x-idris',)),
|
| 228 |
+
'IgorLexer': ('pip._vendor.pygments.lexers.igor', 'Igor', ('igor', 'igorpro'), ('*.ipf',), ('text/ipf',)),
|
| 229 |
+
'Inform6Lexer': ('pip._vendor.pygments.lexers.int_fiction', 'Inform 6', ('inform6', 'i6'), ('*.inf',), ()),
|
| 230 |
+
'Inform6TemplateLexer': ('pip._vendor.pygments.lexers.int_fiction', 'Inform 6 template', ('i6t',), ('*.i6t',), ()),
|
| 231 |
+
'Inform7Lexer': ('pip._vendor.pygments.lexers.int_fiction', 'Inform 7', ('inform7', 'i7'), ('*.ni', '*.i7x'), ()),
|
| 232 |
+
'IniLexer': ('pip._vendor.pygments.lexers.configs', 'INI', ('ini', 'cfg', 'dosini'), ('*.ini', '*.cfg', '*.inf', '.editorconfig'), ('text/x-ini', 'text/inf')),
|
| 233 |
+
'IoLexer': ('pip._vendor.pygments.lexers.iolang', 'Io', ('io',), ('*.io',), ('text/x-iosrc',)),
|
| 234 |
+
'IokeLexer': ('pip._vendor.pygments.lexers.jvm', 'Ioke', ('ioke', 'ik'), ('*.ik',), ('text/x-iokesrc',)),
|
| 235 |
+
'IrcLogsLexer': ('pip._vendor.pygments.lexers.textfmts', 'IRC logs', ('irc',), ('*.weechatlog',), ('text/x-irclog',)),
|
| 236 |
+
'IsabelleLexer': ('pip._vendor.pygments.lexers.theorem', 'Isabelle', ('isabelle',), ('*.thy',), ('text/x-isabelle',)),
|
| 237 |
+
'JLexer': ('pip._vendor.pygments.lexers.j', 'J', ('j',), ('*.ijs',), ('text/x-j',)),
|
| 238 |
+
'JMESPathLexer': ('pip._vendor.pygments.lexers.jmespath', 'JMESPath', ('jmespath', 'jp'), ('*.jp',), ()),
|
| 239 |
+
'JSLTLexer': ('pip._vendor.pygments.lexers.jslt', 'JSLT', ('jslt',), ('*.jslt',), ('text/x-jslt',)),
|
| 240 |
+
'JagsLexer': ('pip._vendor.pygments.lexers.modeling', 'JAGS', ('jags',), ('*.jag', '*.bug'), ()),
|
| 241 |
+
'JanetLexer': ('pip._vendor.pygments.lexers.lisp', 'Janet', ('janet',), ('*.janet', '*.jdn'), ('text/x-janet', 'application/x-janet')),
|
| 242 |
+
'JasminLexer': ('pip._vendor.pygments.lexers.jvm', 'Jasmin', ('jasmin', 'jasminxt'), ('*.j',), ()),
|
| 243 |
+
'JavaLexer': ('pip._vendor.pygments.lexers.jvm', 'Java', ('java',), ('*.java',), ('text/x-java',)),
|
| 244 |
+
'JavascriptDjangoLexer': ('pip._vendor.pygments.lexers.templates', 'JavaScript+Django/Jinja', ('javascript+django', 'js+django', 'javascript+jinja', 'js+jinja'), ('*.js.j2', '*.js.jinja2'), ('application/x-javascript+django', 'application/x-javascript+jinja', 'text/x-javascript+django', 'text/x-javascript+jinja', 'text/javascript+django', 'text/javascript+jinja')),
|
| 245 |
+
'JavascriptErbLexer': ('pip._vendor.pygments.lexers.templates', 'JavaScript+Ruby', ('javascript+ruby', 'js+ruby', 'javascript+erb', 'js+erb'), (), ('application/x-javascript+ruby', 'text/x-javascript+ruby', 'text/javascript+ruby')),
|
| 246 |
+
'JavascriptGenshiLexer': ('pip._vendor.pygments.lexers.templates', 'JavaScript+Genshi Text', ('js+genshitext', 'js+genshi', 'javascript+genshitext', 'javascript+genshi'), (), ('application/x-javascript+genshi', 'text/x-javascript+genshi', 'text/javascript+genshi')),
|
| 247 |
+
'JavascriptLexer': ('pip._vendor.pygments.lexers.javascript', 'JavaScript', ('javascript', 'js'), ('*.js', '*.jsm', '*.mjs', '*.cjs'), ('application/javascript', 'application/x-javascript', 'text/x-javascript', 'text/javascript')),
|
| 248 |
+
'JavascriptPhpLexer': ('pip._vendor.pygments.lexers.templates', 'JavaScript+PHP', ('javascript+php', 'js+php'), (), ('application/x-javascript+php', 'text/x-javascript+php', 'text/javascript+php')),
|
| 249 |
+
'JavascriptSmartyLexer': ('pip._vendor.pygments.lexers.templates', 'JavaScript+Smarty', ('javascript+smarty', 'js+smarty'), (), ('application/x-javascript+smarty', 'text/x-javascript+smarty', 'text/javascript+smarty')),
|
| 250 |
+
'JavascriptUL4Lexer': ('pip._vendor.pygments.lexers.ul4', 'Javascript+UL4', ('js+ul4',), ('*.jsul4',), ()),
|
| 251 |
+
'JclLexer': ('pip._vendor.pygments.lexers.scripting', 'JCL', ('jcl',), ('*.jcl',), ('text/x-jcl',)),
|
| 252 |
+
'JsgfLexer': ('pip._vendor.pygments.lexers.grammar_notation', 'JSGF', ('jsgf',), ('*.jsgf',), ('application/jsgf', 'application/x-jsgf', 'text/jsgf')),
|
| 253 |
+
'Json5Lexer': ('pip._vendor.pygments.lexers.json5', 'JSON5', ('json5',), ('*.json5',), ()),
|
| 254 |
+
'JsonBareObjectLexer': ('pip._vendor.pygments.lexers.data', 'JSONBareObject', (), (), ()),
|
| 255 |
+
'JsonLdLexer': ('pip._vendor.pygments.lexers.data', 'JSON-LD', ('jsonld', 'json-ld'), ('*.jsonld',), ('application/ld+json',)),
|
| 256 |
+
'JsonLexer': ('pip._vendor.pygments.lexers.data', 'JSON', ('json', 'json-object'), ('*.json', '*.jsonl', '*.ndjson', 'Pipfile.lock', '*.module', '*.xc'), ('application/json', 'application/json-object', 'application/x-ndjson', 'application/jsonl', 'application/json-seq')),
|
| 257 |
+
'JsonnetLexer': ('pip._vendor.pygments.lexers.jsonnet', 'Jsonnet', ('jsonnet',), ('*.jsonnet', '*.libsonnet'), ()),
|
| 258 |
+
'JspLexer': ('pip._vendor.pygments.lexers.templates', 'Java Server Page', ('jsp',), ('*.jsp',), ('application/x-jsp',)),
|
| 259 |
+
'JsxLexer': ('pip._vendor.pygments.lexers.jsx', 'JSX', ('jsx', 'react'), ('*.jsx', '*.react'), ('text/jsx', 'text/typescript-jsx')),
|
| 260 |
+
'JuliaConsoleLexer': ('pip._vendor.pygments.lexers.julia', 'Julia console', ('jlcon', 'julia-repl'), (), ()),
|
| 261 |
+
'JuliaLexer': ('pip._vendor.pygments.lexers.julia', 'Julia', ('julia', 'jl'), ('*.jl',), ('text/x-julia', 'application/x-julia')),
|
| 262 |
+
'JuttleLexer': ('pip._vendor.pygments.lexers.javascript', 'Juttle', ('juttle',), ('*.juttle',), ('application/juttle', 'application/x-juttle', 'text/x-juttle', 'text/juttle')),
|
| 263 |
+
'KLexer': ('pip._vendor.pygments.lexers.q', 'K', ('k',), ('*.k',), ()),
|
| 264 |
+
'KalLexer': ('pip._vendor.pygments.lexers.javascript', 'Kal', ('kal',), ('*.kal',), ('text/kal', 'application/kal')),
|
| 265 |
+
'KconfigLexer': ('pip._vendor.pygments.lexers.configs', 'Kconfig', ('kconfig', 'menuconfig', 'linux-config', 'kernel-config'), ('Kconfig*', '*Config.in*', 'external.in*', 'standard-modules.in'), ('text/x-kconfig',)),
|
| 266 |
+
'KernelLogLexer': ('pip._vendor.pygments.lexers.textfmts', 'Kernel log', ('kmsg', 'dmesg'), ('*.kmsg', '*.dmesg'), ()),
|
| 267 |
+
'KokaLexer': ('pip._vendor.pygments.lexers.haskell', 'Koka', ('koka',), ('*.kk', '*.kki'), ('text/x-koka',)),
|
| 268 |
+
'KotlinLexer': ('pip._vendor.pygments.lexers.jvm', 'Kotlin', ('kotlin',), ('*.kt', '*.kts'), ('text/x-kotlin',)),
|
| 269 |
+
'KuinLexer': ('pip._vendor.pygments.lexers.kuin', 'Kuin', ('kuin',), ('*.kn',), ()),
|
| 270 |
+
'KustoLexer': ('pip._vendor.pygments.lexers.kusto', 'Kusto', ('kql', 'kusto'), ('*.kql', '*.kusto', '.csl'), ()),
|
| 271 |
+
'LSLLexer': ('pip._vendor.pygments.lexers.scripting', 'LSL', ('lsl',), ('*.lsl',), ('text/x-lsl',)),
|
| 272 |
+
'LassoCssLexer': ('pip._vendor.pygments.lexers.templates', 'CSS+Lasso', ('css+lasso',), (), ('text/css+lasso',)),
|
| 273 |
+
'LassoHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Lasso', ('html+lasso',), (), ('text/html+lasso', 'application/x-httpd-lasso', 'application/x-httpd-lasso[89]')),
|
| 274 |
+
'LassoJavascriptLexer': ('pip._vendor.pygments.lexers.templates', 'JavaScript+Lasso', ('javascript+lasso', 'js+lasso'), (), ('application/x-javascript+lasso', 'text/x-javascript+lasso', 'text/javascript+lasso')),
|
| 275 |
+
'LassoLexer': ('pip._vendor.pygments.lexers.javascript', 'Lasso', ('lasso', 'lassoscript'), ('*.lasso', '*.lasso[89]'), ('text/x-lasso',)),
|
| 276 |
+
'LassoXmlLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Lasso', ('xml+lasso',), (), ('application/xml+lasso',)),
|
| 277 |
+
'LdaprcLexer': ('pip._vendor.pygments.lexers.ldap', 'LDAP configuration file', ('ldapconf', 'ldaprc'), ('.ldaprc', 'ldaprc', 'ldap.conf'), ('text/x-ldapconf',)),
|
| 278 |
+
'LdifLexer': ('pip._vendor.pygments.lexers.ldap', 'LDIF', ('ldif',), ('*.ldif',), ('text/x-ldif',)),
|
| 279 |
+
'Lean3Lexer': ('pip._vendor.pygments.lexers.lean', 'Lean', ('lean', 'lean3'), ('*.lean',), ('text/x-lean', 'text/x-lean3')),
|
| 280 |
+
'Lean4Lexer': ('pip._vendor.pygments.lexers.lean', 'Lean4', ('lean4',), ('*.lean',), ('text/x-lean4',)),
|
| 281 |
+
'LessCssLexer': ('pip._vendor.pygments.lexers.css', 'LessCss', ('less',), ('*.less',), ('text/x-less-css',)),
|
| 282 |
+
'LighttpdConfLexer': ('pip._vendor.pygments.lexers.configs', 'Lighttpd configuration file', ('lighttpd', 'lighty'), ('lighttpd.conf',), ('text/x-lighttpd-conf',)),
|
| 283 |
+
'LilyPondLexer': ('pip._vendor.pygments.lexers.lilypond', 'LilyPond', ('lilypond',), ('*.ly',), ()),
|
| 284 |
+
'LimboLexer': ('pip._vendor.pygments.lexers.inferno', 'Limbo', ('limbo',), ('*.b',), ('text/limbo',)),
|
| 285 |
+
'LiquidLexer': ('pip._vendor.pygments.lexers.templates', 'liquid', ('liquid',), ('*.liquid',), ()),
|
| 286 |
+
'LiterateAgdaLexer': ('pip._vendor.pygments.lexers.haskell', 'Literate Agda', ('literate-agda', 'lagda'), ('*.lagda',), ('text/x-literate-agda',)),
|
| 287 |
+
'LiterateCryptolLexer': ('pip._vendor.pygments.lexers.haskell', 'Literate Cryptol', ('literate-cryptol', 'lcryptol', 'lcry'), ('*.lcry',), ('text/x-literate-cryptol',)),
|
| 288 |
+
'LiterateHaskellLexer': ('pip._vendor.pygments.lexers.haskell', 'Literate Haskell', ('literate-haskell', 'lhaskell', 'lhs'), ('*.lhs',), ('text/x-literate-haskell',)),
|
| 289 |
+
'LiterateIdrisLexer': ('pip._vendor.pygments.lexers.haskell', 'Literate Idris', ('literate-idris', 'lidris', 'lidr'), ('*.lidr',), ('text/x-literate-idris',)),
|
| 290 |
+
'LiveScriptLexer': ('pip._vendor.pygments.lexers.javascript', 'LiveScript', ('livescript', 'live-script'), ('*.ls',), ('text/livescript',)),
|
| 291 |
+
'LlvmLexer': ('pip._vendor.pygments.lexers.asm', 'LLVM', ('llvm',), ('*.ll',), ('text/x-llvm',)),
|
| 292 |
+
'LlvmMirBodyLexer': ('pip._vendor.pygments.lexers.asm', 'LLVM-MIR Body', ('llvm-mir-body',), (), ()),
|
| 293 |
+
'LlvmMirLexer': ('pip._vendor.pygments.lexers.asm', 'LLVM-MIR', ('llvm-mir',), ('*.mir',), ()),
|
| 294 |
+
'LogosLexer': ('pip._vendor.pygments.lexers.objective', 'Logos', ('logos',), ('*.x', '*.xi', '*.xm', '*.xmi'), ('text/x-logos',)),
|
| 295 |
+
'LogtalkLexer': ('pip._vendor.pygments.lexers.prolog', 'Logtalk', ('logtalk',), ('*.lgt', '*.logtalk'), ('text/x-logtalk',)),
|
| 296 |
+
'LuaLexer': ('pip._vendor.pygments.lexers.scripting', 'Lua', ('lua',), ('*.lua', '*.wlua'), ('text/x-lua', 'application/x-lua')),
|
| 297 |
+
'LuauLexer': ('pip._vendor.pygments.lexers.scripting', 'Luau', ('luau',), ('*.luau',), ()),
|
| 298 |
+
'MCFunctionLexer': ('pip._vendor.pygments.lexers.minecraft', 'MCFunction', ('mcfunction', 'mcf'), ('*.mcfunction',), ('text/mcfunction',)),
|
| 299 |
+
'MCSchemaLexer': ('pip._vendor.pygments.lexers.minecraft', 'MCSchema', ('mcschema',), ('*.mcschema',), ('text/mcschema',)),
|
| 300 |
+
'MIMELexer': ('pip._vendor.pygments.lexers.mime', 'MIME', ('mime',), (), ('multipart/mixed', 'multipart/related', 'multipart/alternative')),
|
| 301 |
+
'MIPSLexer': ('pip._vendor.pygments.lexers.mips', 'MIPS', ('mips',), ('*.mips', '*.MIPS'), ()),
|
| 302 |
+
'MOOCodeLexer': ('pip._vendor.pygments.lexers.scripting', 'MOOCode', ('moocode', 'moo'), ('*.moo',), ('text/x-moocode',)),
|
| 303 |
+
'MSDOSSessionLexer': ('pip._vendor.pygments.lexers.shell', 'MSDOS Session', ('doscon',), (), ()),
|
| 304 |
+
'Macaulay2Lexer': ('pip._vendor.pygments.lexers.macaulay2', 'Macaulay2', ('macaulay2',), ('*.m2',), ()),
|
| 305 |
+
'MakefileLexer': ('pip._vendor.pygments.lexers.make', 'Makefile', ('make', 'makefile', 'mf', 'bsdmake'), ('*.mak', '*.mk', 'Makefile', 'makefile', 'Makefile.*', 'GNUmakefile'), ('text/x-makefile',)),
|
| 306 |
+
'MakoCssLexer': ('pip._vendor.pygments.lexers.templates', 'CSS+Mako', ('css+mako',), (), ('text/css+mako',)),
|
| 307 |
+
'MakoHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Mako', ('html+mako',), (), ('text/html+mako',)),
|
| 308 |
+
'MakoJavascriptLexer': ('pip._vendor.pygments.lexers.templates', 'JavaScript+Mako', ('javascript+mako', 'js+mako'), (), ('application/x-javascript+mako', 'text/x-javascript+mako', 'text/javascript+mako')),
|
| 309 |
+
'MakoLexer': ('pip._vendor.pygments.lexers.templates', 'Mako', ('mako',), ('*.mao',), ('application/x-mako',)),
|
| 310 |
+
'MakoXmlLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Mako', ('xml+mako',), (), ('application/xml+mako',)),
|
| 311 |
+
'MapleLexer': ('pip._vendor.pygments.lexers.maple', 'Maple', ('maple',), ('*.mpl', '*.mi', '*.mm'), ('text/x-maple',)),
|
| 312 |
+
'MaqlLexer': ('pip._vendor.pygments.lexers.business', 'MAQL', ('maql',), ('*.maql',), ('text/x-gooddata-maql', 'application/x-gooddata-maql')),
|
| 313 |
+
'MarkdownLexer': ('pip._vendor.pygments.lexers.markup', 'Markdown', ('markdown', 'md'), ('*.md', '*.markdown'), ('text/x-markdown',)),
|
| 314 |
+
'MaskLexer': ('pip._vendor.pygments.lexers.javascript', 'Mask', ('mask',), ('*.mask',), ('text/x-mask',)),
|
| 315 |
+
'MasonLexer': ('pip._vendor.pygments.lexers.templates', 'Mason', ('mason',), ('*.m', '*.mhtml', '*.mc', '*.mi', 'autohandler', 'dhandler'), ('application/x-mason',)),
|
| 316 |
+
'MathematicaLexer': ('pip._vendor.pygments.lexers.algebra', 'Mathematica', ('mathematica', 'mma', 'nb', 'wl', 'wolfram'), ('*.nb', '*.cdf', '*.nbp', '*.ma', '*.wl', '*.wls'), ('application/mathematica', 'application/vnd.wolfram.mathematica', 'application/vnd.wolfram.mathematica.package', 'application/vnd.wolfram.cdf', 'application/vnd.wolfram.wl')),
|
| 317 |
+
'MatlabLexer': ('pip._vendor.pygments.lexers.matlab', 'Matlab', ('matlab',), ('*.m',), ('text/matlab',)),
|
| 318 |
+
'MatlabSessionLexer': ('pip._vendor.pygments.lexers.matlab', 'Matlab session', ('matlabsession',), (), ()),
|
| 319 |
+
'MaximaLexer': ('pip._vendor.pygments.lexers.maxima', 'Maxima', ('maxima', 'macsyma'), ('*.mac', '*.max'), ()),
|
| 320 |
+
'MesonLexer': ('pip._vendor.pygments.lexers.meson', 'Meson', ('meson', 'meson.build'), ('meson.build', 'meson.options', 'meson_options.txt'), ('text/x-meson',)),
|
| 321 |
+
'MiniDLexer': ('pip._vendor.pygments.lexers.d', 'MiniD', ('minid',), (), ('text/x-minidsrc',)),
|
| 322 |
+
'MiniScriptLexer': ('pip._vendor.pygments.lexers.scripting', 'MiniScript', ('miniscript', 'ms'), ('*.ms',), ('text/x-minicript', 'application/x-miniscript')),
|
| 323 |
+
'ModelicaLexer': ('pip._vendor.pygments.lexers.modeling', 'Modelica', ('modelica',), ('*.mo',), ('text/x-modelica',)),
|
| 324 |
+
'Modula2Lexer': ('pip._vendor.pygments.lexers.modula2', 'Modula-2', ('modula2', 'm2'), ('*.def', '*.mod'), ('text/x-modula2',)),
|
| 325 |
+
'MoinWikiLexer': ('pip._vendor.pygments.lexers.markup', 'MoinMoin/Trac Wiki markup', ('trac-wiki', 'moin'), (), ('text/x-trac-wiki',)),
|
| 326 |
+
'MojoLexer': ('pip._vendor.pygments.lexers.mojo', 'Mojo', ('mojo', '🔥'), ('*.mojo', '*.🔥'), ('text/x-mojo', 'application/x-mojo')),
|
| 327 |
+
'MonkeyLexer': ('pip._vendor.pygments.lexers.basic', 'Monkey', ('monkey',), ('*.monkey',), ('text/x-monkey',)),
|
| 328 |
+
'MonteLexer': ('pip._vendor.pygments.lexers.monte', 'Monte', ('monte',), ('*.mt',), ()),
|
| 329 |
+
'MoonScriptLexer': ('pip._vendor.pygments.lexers.scripting', 'MoonScript', ('moonscript', 'moon'), ('*.moon',), ('text/x-moonscript', 'application/x-moonscript')),
|
| 330 |
+
'MoselLexer': ('pip._vendor.pygments.lexers.mosel', 'Mosel', ('mosel',), ('*.mos',), ()),
|
| 331 |
+
'MozPreprocCssLexer': ('pip._vendor.pygments.lexers.markup', 'CSS+mozpreproc', ('css+mozpreproc',), ('*.css.in',), ()),
|
| 332 |
+
'MozPreprocHashLexer': ('pip._vendor.pygments.lexers.markup', 'mozhashpreproc', ('mozhashpreproc',), (), ()),
|
| 333 |
+
'MozPreprocJavascriptLexer': ('pip._vendor.pygments.lexers.markup', 'Javascript+mozpreproc', ('javascript+mozpreproc',), ('*.js.in',), ()),
|
| 334 |
+
'MozPreprocPercentLexer': ('pip._vendor.pygments.lexers.markup', 'mozpercentpreproc', ('mozpercentpreproc',), (), ()),
|
| 335 |
+
'MozPreprocXulLexer': ('pip._vendor.pygments.lexers.markup', 'XUL+mozpreproc', ('xul+mozpreproc',), ('*.xul.in',), ()),
|
| 336 |
+
'MqlLexer': ('pip._vendor.pygments.lexers.c_like', 'MQL', ('mql', 'mq4', 'mq5', 'mql4', 'mql5'), ('*.mq4', '*.mq5', '*.mqh'), ('text/x-mql',)),
|
| 337 |
+
'MscgenLexer': ('pip._vendor.pygments.lexers.dsls', 'Mscgen', ('mscgen', 'msc'), ('*.msc',), ()),
|
| 338 |
+
'MuPADLexer': ('pip._vendor.pygments.lexers.algebra', 'MuPAD', ('mupad',), ('*.mu',), ()),
|
| 339 |
+
'MxmlLexer': ('pip._vendor.pygments.lexers.actionscript', 'MXML', ('mxml',), ('*.mxml',), ()),
|
| 340 |
+
'MySqlLexer': ('pip._vendor.pygments.lexers.sql', 'MySQL', ('mysql',), (), ('text/x-mysql',)),
|
| 341 |
+
'MyghtyCssLexer': ('pip._vendor.pygments.lexers.templates', 'CSS+Myghty', ('css+myghty',), (), ('text/css+myghty',)),
|
| 342 |
+
'MyghtyHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Myghty', ('html+myghty',), (), ('text/html+myghty',)),
|
| 343 |
+
'MyghtyJavascriptLexer': ('pip._vendor.pygments.lexers.templates', 'JavaScript+Myghty', ('javascript+myghty', 'js+myghty'), (), ('application/x-javascript+myghty', 'text/x-javascript+myghty', 'text/javascript+mygthy')),
|
| 344 |
+
'MyghtyLexer': ('pip._vendor.pygments.lexers.templates', 'Myghty', ('myghty',), ('*.myt', 'autodelegate'), ('application/x-myghty',)),
|
| 345 |
+
'MyghtyXmlLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Myghty', ('xml+myghty',), (), ('application/xml+myghty',)),
|
| 346 |
+
'NCLLexer': ('pip._vendor.pygments.lexers.ncl', 'NCL', ('ncl',), ('*.ncl',), ('text/ncl',)),
|
| 347 |
+
'NSISLexer': ('pip._vendor.pygments.lexers.installers', 'NSIS', ('nsis', 'nsi', 'nsh'), ('*.nsi', '*.nsh'), ('text/x-nsis',)),
|
| 348 |
+
'NasmLexer': ('pip._vendor.pygments.lexers.asm', 'NASM', ('nasm',), ('*.asm', '*.ASM', '*.nasm'), ('text/x-nasm',)),
|
| 349 |
+
'NasmObjdumpLexer': ('pip._vendor.pygments.lexers.asm', 'objdump-nasm', ('objdump-nasm',), ('*.objdump-intel',), ('text/x-nasm-objdump',)),
|
| 350 |
+
'NemerleLexer': ('pip._vendor.pygments.lexers.dotnet', 'Nemerle', ('nemerle',), ('*.n',), ('text/x-nemerle',)),
|
| 351 |
+
'NesCLexer': ('pip._vendor.pygments.lexers.c_like', 'nesC', ('nesc',), ('*.nc',), ('text/x-nescsrc',)),
|
| 352 |
+
'NestedTextLexer': ('pip._vendor.pygments.lexers.configs', 'NestedText', ('nestedtext', 'nt'), ('*.nt',), ()),
|
| 353 |
+
'NewLispLexer': ('pip._vendor.pygments.lexers.lisp', 'NewLisp', ('newlisp',), ('*.lsp', '*.nl', '*.kif'), ('text/x-newlisp', 'application/x-newlisp')),
|
| 354 |
+
'NewspeakLexer': ('pip._vendor.pygments.lexers.smalltalk', 'Newspeak', ('newspeak',), ('*.ns2',), ('text/x-newspeak',)),
|
| 355 |
+
'NginxConfLexer': ('pip._vendor.pygments.lexers.configs', 'Nginx configuration file', ('nginx',), ('nginx.conf',), ('text/x-nginx-conf',)),
|
| 356 |
+
'NimrodLexer': ('pip._vendor.pygments.lexers.nimrod', 'Nimrod', ('nimrod', 'nim'), ('*.nim', '*.nimrod'), ('text/x-nim',)),
|
| 357 |
+
'NitLexer': ('pip._vendor.pygments.lexers.nit', 'Nit', ('nit',), ('*.nit',), ()),
|
| 358 |
+
'NixLexer': ('pip._vendor.pygments.lexers.nix', 'Nix', ('nixos', 'nix'), ('*.nix',), ('text/x-nix',)),
|
| 359 |
+
'NodeConsoleLexer': ('pip._vendor.pygments.lexers.javascript', 'Node.js REPL console session', ('nodejsrepl',), (), ('text/x-nodejsrepl',)),
|
| 360 |
+
'NotmuchLexer': ('pip._vendor.pygments.lexers.textfmts', 'Notmuch', ('notmuch',), (), ()),
|
| 361 |
+
'NuSMVLexer': ('pip._vendor.pygments.lexers.smv', 'NuSMV', ('nusmv',), ('*.smv',), ()),
|
| 362 |
+
'NumPyLexer': ('pip._vendor.pygments.lexers.python', 'NumPy', ('numpy',), (), ()),
|
| 363 |
+
'NumbaIRLexer': ('pip._vendor.pygments.lexers.numbair', 'Numba_IR', ('numba_ir', 'numbair'), ('*.numba_ir',), ('text/x-numba_ir', 'text/x-numbair')),
|
| 364 |
+
'ObjdumpLexer': ('pip._vendor.pygments.lexers.asm', 'objdump', ('objdump',), ('*.objdump',), ('text/x-objdump',)),
|
| 365 |
+
'ObjectiveCLexer': ('pip._vendor.pygments.lexers.objective', 'Objective-C', ('objective-c', 'objectivec', 'obj-c', 'objc'), ('*.m', '*.h'), ('text/x-objective-c',)),
|
| 366 |
+
'ObjectiveCppLexer': ('pip._vendor.pygments.lexers.objective', 'Objective-C++', ('objective-c++', 'objectivec++', 'obj-c++', 'objc++'), ('*.mm', '*.hh'), ('text/x-objective-c++',)),
|
| 367 |
+
'ObjectiveJLexer': ('pip._vendor.pygments.lexers.javascript', 'Objective-J', ('objective-j', 'objectivej', 'obj-j', 'objj'), ('*.j',), ('text/x-objective-j',)),
|
| 368 |
+
'OcamlLexer': ('pip._vendor.pygments.lexers.ml', 'OCaml', ('ocaml',), ('*.ml', '*.mli', '*.mll', '*.mly'), ('text/x-ocaml',)),
|
| 369 |
+
'OctaveLexer': ('pip._vendor.pygments.lexers.matlab', 'Octave', ('octave',), ('*.m',), ('text/octave',)),
|
| 370 |
+
'OdinLexer': ('pip._vendor.pygments.lexers.archetype', 'ODIN', ('odin',), ('*.odin',), ('text/odin',)),
|
| 371 |
+
'OmgIdlLexer': ('pip._vendor.pygments.lexers.c_like', 'OMG Interface Definition Language', ('omg-idl',), ('*.idl', '*.pidl'), ()),
|
| 372 |
+
'OocLexer': ('pip._vendor.pygments.lexers.ooc', 'Ooc', ('ooc',), ('*.ooc',), ('text/x-ooc',)),
|
| 373 |
+
'OpaLexer': ('pip._vendor.pygments.lexers.ml', 'Opa', ('opa',), ('*.opa',), ('text/x-opa',)),
|
| 374 |
+
'OpenEdgeLexer': ('pip._vendor.pygments.lexers.business', 'OpenEdge ABL', ('openedge', 'abl', 'progress'), ('*.p', '*.cls'), ('text/x-openedge', 'application/x-openedge')),
|
| 375 |
+
'OpenScadLexer': ('pip._vendor.pygments.lexers.openscad', 'OpenSCAD', ('openscad',), ('*.scad',), ('application/x-openscad',)),
|
| 376 |
+
'OrgLexer': ('pip._vendor.pygments.lexers.markup', 'Org Mode', ('org', 'orgmode', 'org-mode'), ('*.org',), ('text/org',)),
|
| 377 |
+
'OutputLexer': ('pip._vendor.pygments.lexers.special', 'Text output', ('output',), (), ()),
|
| 378 |
+
'PacmanConfLexer': ('pip._vendor.pygments.lexers.configs', 'PacmanConf', ('pacmanconf',), ('pacman.conf',), ()),
|
| 379 |
+
'PanLexer': ('pip._vendor.pygments.lexers.dsls', 'Pan', ('pan',), ('*.pan',), ()),
|
| 380 |
+
'ParaSailLexer': ('pip._vendor.pygments.lexers.parasail', 'ParaSail', ('parasail',), ('*.psi', '*.psl'), ('text/x-parasail',)),
|
| 381 |
+
'PawnLexer': ('pip._vendor.pygments.lexers.pawn', 'Pawn', ('pawn',), ('*.p', '*.pwn', '*.inc'), ('text/x-pawn',)),
|
| 382 |
+
'PddlLexer': ('pip._vendor.pygments.lexers.pddl', 'PDDL', ('pddl',), ('*.pddl',), ()),
|
| 383 |
+
'PegLexer': ('pip._vendor.pygments.lexers.grammar_notation', 'PEG', ('peg',), ('*.peg',), ('text/x-peg',)),
|
| 384 |
+
'Perl6Lexer': ('pip._vendor.pygments.lexers.perl', 'Perl6', ('perl6', 'pl6', 'raku'), ('*.pl', '*.pm', '*.nqp', '*.p6', '*.6pl', '*.p6l', '*.pl6', '*.6pm', '*.p6m', '*.pm6', '*.t', '*.raku', '*.rakumod', '*.rakutest', '*.rakudoc'), ('text/x-perl6', 'application/x-perl6')),
|
| 385 |
+
'PerlLexer': ('pip._vendor.pygments.lexers.perl', 'Perl', ('perl', 'pl'), ('*.pl', '*.pm', '*.t', '*.perl'), ('text/x-perl', 'application/x-perl')),
|
| 386 |
+
'PhixLexer': ('pip._vendor.pygments.lexers.phix', 'Phix', ('phix',), ('*.exw',), ('text/x-phix',)),
|
| 387 |
+
'PhpLexer': ('pip._vendor.pygments.lexers.php', 'PHP', ('php', 'php3', 'php4', 'php5'), ('*.php', '*.php[345]', '*.inc'), ('text/x-php',)),
|
| 388 |
+
'PigLexer': ('pip._vendor.pygments.lexers.jvm', 'Pig', ('pig',), ('*.pig',), ('text/x-pig',)),
|
| 389 |
+
'PikeLexer': ('pip._vendor.pygments.lexers.c_like', 'Pike', ('pike',), ('*.pike', '*.pmod'), ('text/x-pike',)),
|
| 390 |
+
'PkgConfigLexer': ('pip._vendor.pygments.lexers.configs', 'PkgConfig', ('pkgconfig',), ('*.pc',), ()),
|
| 391 |
+
'PlPgsqlLexer': ('pip._vendor.pygments.lexers.sql', 'PL/pgSQL', ('plpgsql',), (), ('text/x-plpgsql',)),
|
| 392 |
+
'PointlessLexer': ('pip._vendor.pygments.lexers.pointless', 'Pointless', ('pointless',), ('*.ptls',), ()),
|
| 393 |
+
'PonyLexer': ('pip._vendor.pygments.lexers.pony', 'Pony', ('pony',), ('*.pony',), ()),
|
| 394 |
+
'PortugolLexer': ('pip._vendor.pygments.lexers.pascal', 'Portugol', ('portugol',), ('*.alg', '*.portugol'), ()),
|
| 395 |
+
'PostScriptLexer': ('pip._vendor.pygments.lexers.graphics', 'PostScript', ('postscript', 'postscr'), ('*.ps', '*.eps'), ('application/postscript',)),
|
| 396 |
+
'PostgresConsoleLexer': ('pip._vendor.pygments.lexers.sql', 'PostgreSQL console (psql)', ('psql', 'postgresql-console', 'postgres-console'), (), ('text/x-postgresql-psql',)),
|
| 397 |
+
'PostgresExplainLexer': ('pip._vendor.pygments.lexers.sql', 'PostgreSQL EXPLAIN dialect', ('postgres-explain',), ('*.explain',), ('text/x-postgresql-explain',)),
|
| 398 |
+
'PostgresLexer': ('pip._vendor.pygments.lexers.sql', 'PostgreSQL SQL dialect', ('postgresql', 'postgres'), (), ('text/x-postgresql',)),
|
| 399 |
+
'PovrayLexer': ('pip._vendor.pygments.lexers.graphics', 'POVRay', ('pov',), ('*.pov', '*.inc'), ('text/x-povray',)),
|
| 400 |
+
'PowerShellLexer': ('pip._vendor.pygments.lexers.shell', 'PowerShell', ('powershell', 'pwsh', 'posh', 'ps1', 'psm1'), ('*.ps1', '*.psm1'), ('text/x-powershell',)),
|
| 401 |
+
'PowerShellSessionLexer': ('pip._vendor.pygments.lexers.shell', 'PowerShell Session', ('pwsh-session', 'ps1con'), (), ()),
|
| 402 |
+
'PraatLexer': ('pip._vendor.pygments.lexers.praat', 'Praat', ('praat',), ('*.praat', '*.proc', '*.psc'), ()),
|
| 403 |
+
'ProcfileLexer': ('pip._vendor.pygments.lexers.procfile', 'Procfile', ('procfile',), ('Procfile',), ()),
|
| 404 |
+
'PrologLexer': ('pip._vendor.pygments.lexers.prolog', 'Prolog', ('prolog',), ('*.ecl', '*.prolog', '*.pro', '*.pl'), ('text/x-prolog',)),
|
| 405 |
+
'PromQLLexer': ('pip._vendor.pygments.lexers.promql', 'PromQL', ('promql',), ('*.promql',), ()),
|
| 406 |
+
'PromelaLexer': ('pip._vendor.pygments.lexers.c_like', 'Promela', ('promela',), ('*.pml', '*.prom', '*.prm', '*.promela', '*.pr', '*.pm'), ('text/x-promela',)),
|
| 407 |
+
'PropertiesLexer': ('pip._vendor.pygments.lexers.configs', 'Properties', ('properties', 'jproperties'), ('*.properties',), ('text/x-java-properties',)),
|
| 408 |
+
'ProtoBufLexer': ('pip._vendor.pygments.lexers.dsls', 'Protocol Buffer', ('protobuf', 'proto'), ('*.proto',), ()),
|
| 409 |
+
'PrqlLexer': ('pip._vendor.pygments.lexers.prql', 'PRQL', ('prql',), ('*.prql',), ('application/prql', 'application/x-prql')),
|
| 410 |
+
'PsyshConsoleLexer': ('pip._vendor.pygments.lexers.php', 'PsySH console session for PHP', ('psysh',), (), ()),
|
| 411 |
+
'PtxLexer': ('pip._vendor.pygments.lexers.ptx', 'PTX', ('ptx',), ('*.ptx',), ('text/x-ptx',)),
|
| 412 |
+
'PugLexer': ('pip._vendor.pygments.lexers.html', 'Pug', ('pug', 'jade'), ('*.pug', '*.jade'), ('text/x-pug', 'text/x-jade')),
|
| 413 |
+
'PuppetLexer': ('pip._vendor.pygments.lexers.dsls', 'Puppet', ('puppet',), ('*.pp',), ()),
|
| 414 |
+
'PyPyLogLexer': ('pip._vendor.pygments.lexers.console', 'PyPy Log', ('pypylog', 'pypy'), ('*.pypylog',), ('application/x-pypylog',)),
|
| 415 |
+
'Python2Lexer': ('pip._vendor.pygments.lexers.python', 'Python 2.x', ('python2', 'py2'), (), ('text/x-python2', 'application/x-python2')),
|
| 416 |
+
'Python2TracebackLexer': ('pip._vendor.pygments.lexers.python', 'Python 2.x Traceback', ('py2tb',), ('*.py2tb',), ('text/x-python2-traceback',)),
|
| 417 |
+
'PythonConsoleLexer': ('pip._vendor.pygments.lexers.python', 'Python console session', ('pycon', 'python-console'), (), ('text/x-python-doctest',)),
|
| 418 |
+
'PythonLexer': ('pip._vendor.pygments.lexers.python', 'Python', ('python', 'py', 'sage', 'python3', 'py3', 'bazel', 'starlark', 'pyi'), ('*.py', '*.pyw', '*.pyi', '*.jy', '*.sage', '*.sc', 'SConstruct', 'SConscript', '*.bzl', 'BUCK', 'BUILD', 'BUILD.bazel', 'WORKSPACE', '*.tac', '*.pye'), ('text/x-python', 'application/x-python', 'text/x-python3', 'application/x-python3')),
|
| 419 |
+
'PythonTracebackLexer': ('pip._vendor.pygments.lexers.python', 'Python Traceback', ('pytb', 'py3tb'), ('*.pytb', '*.py3tb'), ('text/x-python-traceback', 'text/x-python3-traceback')),
|
| 420 |
+
'PythonUL4Lexer': ('pip._vendor.pygments.lexers.ul4', 'Python+UL4', ('py+ul4',), ('*.pyul4',), ()),
|
| 421 |
+
'QBasicLexer': ('pip._vendor.pygments.lexers.basic', 'QBasic', ('qbasic', 'basic'), ('*.BAS', '*.bas'), ('text/basic',)),
|
| 422 |
+
'QLexer': ('pip._vendor.pygments.lexers.q', 'Q', ('q',), ('*.q',), ()),
|
| 423 |
+
'QVToLexer': ('pip._vendor.pygments.lexers.qvt', 'QVTO', ('qvto', 'qvt'), ('*.qvto',), ()),
|
| 424 |
+
'QlikLexer': ('pip._vendor.pygments.lexers.qlik', 'Qlik', ('qlik', 'qlikview', 'qliksense', 'qlikscript'), ('*.qvs', '*.qvw'), ()),
|
| 425 |
+
'QmlLexer': ('pip._vendor.pygments.lexers.webmisc', 'QML', ('qml', 'qbs'), ('*.qml', '*.qbs'), ('application/x-qml', 'application/x-qt.qbs+qml')),
|
| 426 |
+
'RConsoleLexer': ('pip._vendor.pygments.lexers.r', 'RConsole', ('rconsole', 'rout'), ('*.Rout',), ()),
|
| 427 |
+
'RNCCompactLexer': ('pip._vendor.pygments.lexers.rnc', 'Relax-NG Compact', ('rng-compact', 'rnc'), ('*.rnc',), ()),
|
| 428 |
+
'RPMSpecLexer': ('pip._vendor.pygments.lexers.installers', 'RPMSpec', ('spec',), ('*.spec',), ('text/x-rpm-spec',)),
|
| 429 |
+
'RacketLexer': ('pip._vendor.pygments.lexers.lisp', 'Racket', ('racket', 'rkt'), ('*.rkt', '*.rktd', '*.rktl'), ('text/x-racket', 'application/x-racket')),
|
| 430 |
+
'RagelCLexer': ('pip._vendor.pygments.lexers.parsers', 'Ragel in C Host', ('ragel-c',), ('*.rl',), ()),
|
| 431 |
+
'RagelCppLexer': ('pip._vendor.pygments.lexers.parsers', 'Ragel in CPP Host', ('ragel-cpp',), ('*.rl',), ()),
|
| 432 |
+
'RagelDLexer': ('pip._vendor.pygments.lexers.parsers', 'Ragel in D Host', ('ragel-d',), ('*.rl',), ()),
|
| 433 |
+
'RagelEmbeddedLexer': ('pip._vendor.pygments.lexers.parsers', 'Embedded Ragel', ('ragel-em',), ('*.rl',), ()),
|
| 434 |
+
'RagelJavaLexer': ('pip._vendor.pygments.lexers.parsers', 'Ragel in Java Host', ('ragel-java',), ('*.rl',), ()),
|
| 435 |
+
'RagelLexer': ('pip._vendor.pygments.lexers.parsers', 'Ragel', ('ragel',), (), ()),
|
| 436 |
+
'RagelObjectiveCLexer': ('pip._vendor.pygments.lexers.parsers', 'Ragel in Objective C Host', ('ragel-objc',), ('*.rl',), ()),
|
| 437 |
+
'RagelRubyLexer': ('pip._vendor.pygments.lexers.parsers', 'Ragel in Ruby Host', ('ragel-ruby', 'ragel-rb'), ('*.rl',), ()),
|
| 438 |
+
'RawTokenLexer': ('pip._vendor.pygments.lexers.special', 'Raw token data', (), (), ('application/x-pygments-tokens',)),
|
| 439 |
+
'RdLexer': ('pip._vendor.pygments.lexers.r', 'Rd', ('rd',), ('*.Rd',), ('text/x-r-doc',)),
|
| 440 |
+
'ReasonLexer': ('pip._vendor.pygments.lexers.ml', 'ReasonML', ('reasonml', 'reason'), ('*.re', '*.rei'), ('text/x-reasonml',)),
|
| 441 |
+
'RebolLexer': ('pip._vendor.pygments.lexers.rebol', 'REBOL', ('rebol',), ('*.r', '*.r3', '*.reb'), ('text/x-rebol',)),
|
| 442 |
+
'RedLexer': ('pip._vendor.pygments.lexers.rebol', 'Red', ('red', 'red/system'), ('*.red', '*.reds'), ('text/x-red', 'text/x-red-system')),
|
| 443 |
+
'RedcodeLexer': ('pip._vendor.pygments.lexers.esoteric', 'Redcode', ('redcode',), ('*.cw',), ()),
|
| 444 |
+
'RegeditLexer': ('pip._vendor.pygments.lexers.configs', 'reg', ('registry',), ('*.reg',), ('text/x-windows-registry',)),
|
| 445 |
+
'RegoLexer': ('pip._vendor.pygments.lexers.rego', 'Rego', ('rego',), ('*.rego',), ('text/x-rego',)),
|
| 446 |
+
'RellLexer': ('pip._vendor.pygments.lexers.rell', 'Rell', ('rell',), ('*.rell',), ('text/x-rell',)),
|
| 447 |
+
'ResourceLexer': ('pip._vendor.pygments.lexers.resource', 'ResourceBundle', ('resourcebundle', 'resource'), (), ()),
|
| 448 |
+
'RexxLexer': ('pip._vendor.pygments.lexers.scripting', 'Rexx', ('rexx', 'arexx'), ('*.rexx', '*.rex', '*.rx', '*.arexx'), ('text/x-rexx',)),
|
| 449 |
+
'RhtmlLexer': ('pip._vendor.pygments.lexers.templates', 'RHTML', ('rhtml', 'html+erb', 'html+ruby'), ('*.rhtml',), ('text/html+ruby',)),
|
| 450 |
+
'RideLexer': ('pip._vendor.pygments.lexers.ride', 'Ride', ('ride',), ('*.ride',), ('text/x-ride',)),
|
| 451 |
+
'RitaLexer': ('pip._vendor.pygments.lexers.rita', 'Rita', ('rita',), ('*.rita',), ('text/rita',)),
|
| 452 |
+
'RoboconfGraphLexer': ('pip._vendor.pygments.lexers.roboconf', 'Roboconf Graph', ('roboconf-graph',), ('*.graph',), ()),
|
| 453 |
+
'RoboconfInstancesLexer': ('pip._vendor.pygments.lexers.roboconf', 'Roboconf Instances', ('roboconf-instances',), ('*.instances',), ()),
|
| 454 |
+
'RobotFrameworkLexer': ('pip._vendor.pygments.lexers.robotframework', 'RobotFramework', ('robotframework',), ('*.robot', '*.resource'), ('text/x-robotframework',)),
|
| 455 |
+
'RocqLexer': ('pip._vendor.pygments.lexers.theorem', 'Rocq Prover', ('coq', 'rocq', 'rocq-prover'), ('*.v',), ('text/x-coq', 'text/x-rocq')),
|
| 456 |
+
'RqlLexer': ('pip._vendor.pygments.lexers.sql', 'RQL', ('rql',), ('*.rql',), ('text/x-rql',)),
|
| 457 |
+
'RslLexer': ('pip._vendor.pygments.lexers.dsls', 'RSL', ('rsl',), ('*.rsl',), ('text/rsl',)),
|
| 458 |
+
'RstLexer': ('pip._vendor.pygments.lexers.markup', 'reStructuredText', ('restructuredtext', 'rst', 'rest'), ('*.rst', '*.rest'), ('text/x-rst', 'text/prs.fallenstein.rst')),
|
| 459 |
+
'RtsLexer': ('pip._vendor.pygments.lexers.trafficscript', 'TrafficScript', ('trafficscript', 'rts'), ('*.rts',), ()),
|
| 460 |
+
'RubyConsoleLexer': ('pip._vendor.pygments.lexers.ruby', 'Ruby irb session', ('rbcon', 'irb'), (), ('text/x-ruby-shellsession',)),
|
| 461 |
+
'RubyLexer': ('pip._vendor.pygments.lexers.ruby', 'Ruby', ('ruby', 'rb', 'duby'), ('*.rb', '*.rbw', 'Rakefile', '*.rake', '*.gemspec', '*.rbx', '*.duby', 'Gemfile', 'Vagrantfile'), ('text/x-ruby', 'application/x-ruby')),
|
| 462 |
+
'RustLexer': ('pip._vendor.pygments.lexers.rust', 'Rust', ('rust', 'rs'), ('*.rs', '*.rs.in'), ('text/rust', 'text/x-rust')),
|
| 463 |
+
'SASLexer': ('pip._vendor.pygments.lexers.sas', 'SAS', ('sas',), ('*.SAS', '*.sas'), ('text/x-sas', 'text/sas', 'application/x-sas')),
|
| 464 |
+
'SLexer': ('pip._vendor.pygments.lexers.r', 'S', ('splus', 's', 'r'), ('*.S', '*.R', '.Rhistory', '.Rprofile', '.Renviron'), ('text/S-plus', 'text/S', 'text/x-r-source', 'text/x-r', 'text/x-R', 'text/x-r-history', 'text/x-r-profile')),
|
| 465 |
+
'SMLLexer': ('pip._vendor.pygments.lexers.ml', 'Standard ML', ('sml',), ('*.sml', '*.sig', '*.fun'), ('text/x-standardml', 'application/x-standardml')),
|
| 466 |
+
'SNBTLexer': ('pip._vendor.pygments.lexers.minecraft', 'SNBT', ('snbt',), ('*.snbt',), ('text/snbt',)),
|
| 467 |
+
'SarlLexer': ('pip._vendor.pygments.lexers.jvm', 'SARL', ('sarl',), ('*.sarl',), ('text/x-sarl',)),
|
| 468 |
+
'SassLexer': ('pip._vendor.pygments.lexers.css', 'Sass', ('sass',), ('*.sass',), ('text/x-sass',)),
|
| 469 |
+
'SaviLexer': ('pip._vendor.pygments.lexers.savi', 'Savi', ('savi',), ('*.savi',), ()),
|
| 470 |
+
'ScalaLexer': ('pip._vendor.pygments.lexers.jvm', 'Scala', ('scala',), ('*.scala',), ('text/x-scala',)),
|
| 471 |
+
'ScamlLexer': ('pip._vendor.pygments.lexers.html', 'Scaml', ('scaml',), ('*.scaml',), ('text/x-scaml',)),
|
| 472 |
+
'ScdocLexer': ('pip._vendor.pygments.lexers.scdoc', 'scdoc', ('scdoc', 'scd'), ('*.scd', '*.scdoc'), ()),
|
| 473 |
+
'SchemeLexer': ('pip._vendor.pygments.lexers.lisp', 'Scheme', ('scheme', 'scm'), ('*.scm', '*.ss'), ('text/x-scheme', 'application/x-scheme')),
|
| 474 |
+
'ScilabLexer': ('pip._vendor.pygments.lexers.matlab', 'Scilab', ('scilab',), ('*.sci', '*.sce', '*.tst'), ('text/scilab',)),
|
| 475 |
+
'ScssLexer': ('pip._vendor.pygments.lexers.css', 'SCSS', ('scss',), ('*.scss',), ('text/x-scss',)),
|
| 476 |
+
'SedLexer': ('pip._vendor.pygments.lexers.textedit', 'Sed', ('sed', 'gsed', 'ssed'), ('*.sed', '*.[gs]sed'), ('text/x-sed',)),
|
| 477 |
+
'ShExCLexer': ('pip._vendor.pygments.lexers.rdf', 'ShExC', ('shexc', 'shex'), ('*.shex',), ('text/shex',)),
|
| 478 |
+
'ShenLexer': ('pip._vendor.pygments.lexers.lisp', 'Shen', ('shen',), ('*.shen',), ('text/x-shen', 'application/x-shen')),
|
| 479 |
+
'SieveLexer': ('pip._vendor.pygments.lexers.sieve', 'Sieve', ('sieve',), ('*.siv', '*.sieve'), ()),
|
| 480 |
+
'SilverLexer': ('pip._vendor.pygments.lexers.verification', 'Silver', ('silver',), ('*.sil', '*.vpr'), ()),
|
| 481 |
+
'SingularityLexer': ('pip._vendor.pygments.lexers.configs', 'Singularity', ('singularity',), ('*.def', 'Singularity'), ()),
|
| 482 |
+
'SlashLexer': ('pip._vendor.pygments.lexers.slash', 'Slash', ('slash',), ('*.sla',), ()),
|
| 483 |
+
'SlimLexer': ('pip._vendor.pygments.lexers.webmisc', 'Slim', ('slim',), ('*.slim',), ('text/x-slim',)),
|
| 484 |
+
'SlurmBashLexer': ('pip._vendor.pygments.lexers.shell', 'Slurm', ('slurm', 'sbatch'), ('*.sl',), ()),
|
| 485 |
+
'SmaliLexer': ('pip._vendor.pygments.lexers.dalvik', 'Smali', ('smali',), ('*.smali',), ('text/smali',)),
|
| 486 |
+
'SmalltalkLexer': ('pip._vendor.pygments.lexers.smalltalk', 'Smalltalk', ('smalltalk', 'squeak', 'st'), ('*.st',), ('text/x-smalltalk',)),
|
| 487 |
+
'SmartGameFormatLexer': ('pip._vendor.pygments.lexers.sgf', 'SmartGameFormat', ('sgf',), ('*.sgf',), ()),
|
| 488 |
+
'SmartyLexer': ('pip._vendor.pygments.lexers.templates', 'Smarty', ('smarty',), ('*.tpl',), ('application/x-smarty',)),
|
| 489 |
+
'SmithyLexer': ('pip._vendor.pygments.lexers.smithy', 'Smithy', ('smithy',), ('*.smithy',), ()),
|
| 490 |
+
'SnobolLexer': ('pip._vendor.pygments.lexers.snobol', 'Snobol', ('snobol',), ('*.snobol',), ('text/x-snobol',)),
|
| 491 |
+
'SnowballLexer': ('pip._vendor.pygments.lexers.dsls', 'Snowball', ('snowball',), ('*.sbl',), ()),
|
| 492 |
+
'SolidityLexer': ('pip._vendor.pygments.lexers.solidity', 'Solidity', ('solidity',), ('*.sol',), ()),
|
| 493 |
+
'SoongLexer': ('pip._vendor.pygments.lexers.soong', 'Soong', ('androidbp', 'bp', 'soong'), ('Android.bp',), ()),
|
| 494 |
+
'SophiaLexer': ('pip._vendor.pygments.lexers.sophia', 'Sophia', ('sophia',), ('*.aes',), ()),
|
| 495 |
+
'SourcePawnLexer': ('pip._vendor.pygments.lexers.pawn', 'SourcePawn', ('sp',), ('*.sp',), ('text/x-sourcepawn',)),
|
| 496 |
+
'SourcesListLexer': ('pip._vendor.pygments.lexers.installers', 'Debian Sourcelist', ('debsources', 'sourceslist', 'sources.list'), ('sources.list',), ()),
|
| 497 |
+
'SparqlLexer': ('pip._vendor.pygments.lexers.rdf', 'SPARQL', ('sparql',), ('*.rq', '*.sparql'), ('application/sparql-query',)),
|
| 498 |
+
'SpiceLexer': ('pip._vendor.pygments.lexers.spice', 'Spice', ('spice', 'spicelang'), ('*.spice',), ('text/x-spice',)),
|
| 499 |
+
'SqlJinjaLexer': ('pip._vendor.pygments.lexers.templates', 'SQL+Jinja', ('sql+jinja',), ('*.sql', '*.sql.j2', '*.sql.jinja2'), ()),
|
| 500 |
+
'SqlLexer': ('pip._vendor.pygments.lexers.sql', 'SQL', ('sql',), ('*.sql',), ('text/x-sql',)),
|
| 501 |
+
'SqliteConsoleLexer': ('pip._vendor.pygments.lexers.sql', 'sqlite3con', ('sqlite3',), ('*.sqlite3-console',), ('text/x-sqlite3-console',)),
|
| 502 |
+
'SquidConfLexer': ('pip._vendor.pygments.lexers.configs', 'SquidConf', ('squidconf', 'squid.conf', 'squid'), ('squid.conf',), ('text/x-squidconf',)),
|
| 503 |
+
'SrcinfoLexer': ('pip._vendor.pygments.lexers.srcinfo', 'Srcinfo', ('srcinfo',), ('.SRCINFO',), ()),
|
| 504 |
+
'SspLexer': ('pip._vendor.pygments.lexers.templates', 'Scalate Server Page', ('ssp',), ('*.ssp',), ('application/x-ssp',)),
|
| 505 |
+
'StanLexer': ('pip._vendor.pygments.lexers.modeling', 'Stan', ('stan',), ('*.stan',), ()),
|
| 506 |
+
'StataLexer': ('pip._vendor.pygments.lexers.stata', 'Stata', ('stata', 'do'), ('*.do', '*.ado'), ('text/x-stata', 'text/stata', 'application/x-stata')),
|
| 507 |
+
'SuperColliderLexer': ('pip._vendor.pygments.lexers.supercollider', 'SuperCollider', ('supercollider', 'sc'), ('*.sc', '*.scd'), ('application/supercollider', 'text/supercollider')),
|
| 508 |
+
'SwiftLexer': ('pip._vendor.pygments.lexers.objective', 'Swift', ('swift',), ('*.swift',), ('text/x-swift',)),
|
| 509 |
+
'SwigLexer': ('pip._vendor.pygments.lexers.c_like', 'SWIG', ('swig',), ('*.swg', '*.i'), ('text/swig',)),
|
| 510 |
+
'SystemVerilogLexer': ('pip._vendor.pygments.lexers.hdl', 'systemverilog', ('systemverilog', 'sv'), ('*.sv', '*.svh'), ('text/x-systemverilog',)),
|
| 511 |
+
'SystemdLexer': ('pip._vendor.pygments.lexers.configs', 'Systemd', ('systemd',), ('*.service', '*.socket', '*.device', '*.mount', '*.automount', '*.swap', '*.target', '*.path', '*.timer', '*.slice', '*.scope'), ()),
|
| 512 |
+
'TAPLexer': ('pip._vendor.pygments.lexers.testing', 'TAP', ('tap',), ('*.tap',), ()),
|
| 513 |
+
'TNTLexer': ('pip._vendor.pygments.lexers.tnt', 'Typographic Number Theory', ('tnt',), ('*.tnt',), ()),
|
| 514 |
+
'TOMLLexer': ('pip._vendor.pygments.lexers.configs', 'TOML', ('toml',), ('*.toml', 'Pipfile', 'poetry.lock'), ('application/toml',)),
|
| 515 |
+
'TableGenLexer': ('pip._vendor.pygments.lexers.tablegen', 'TableGen', ('tablegen', 'td'), ('*.td',), ()),
|
| 516 |
+
'TactLexer': ('pip._vendor.pygments.lexers.tact', 'Tact', ('tact',), ('*.tact',), ()),
|
| 517 |
+
'Tads3Lexer': ('pip._vendor.pygments.lexers.int_fiction', 'TADS 3', ('tads3',), ('*.t',), ()),
|
| 518 |
+
'TalLexer': ('pip._vendor.pygments.lexers.tal', 'Tal', ('tal', 'uxntal'), ('*.tal',), ('text/x-uxntal',)),
|
| 519 |
+
'TasmLexer': ('pip._vendor.pygments.lexers.asm', 'TASM', ('tasm',), ('*.asm', '*.ASM', '*.tasm'), ('text/x-tasm',)),
|
| 520 |
+
'TclLexer': ('pip._vendor.pygments.lexers.tcl', 'Tcl', ('tcl',), ('*.tcl', '*.rvt'), ('text/x-tcl', 'text/x-script.tcl', 'application/x-tcl')),
|
| 521 |
+
'TcshLexer': ('pip._vendor.pygments.lexers.shell', 'Tcsh', ('tcsh', 'csh'), ('*.tcsh', '*.csh'), ('application/x-csh',)),
|
| 522 |
+
'TcshSessionLexer': ('pip._vendor.pygments.lexers.shell', 'Tcsh Session', ('tcshcon',), (), ()),
|
| 523 |
+
'TeaTemplateLexer': ('pip._vendor.pygments.lexers.templates', 'Tea', ('tea',), ('*.tea',), ('text/x-tea',)),
|
| 524 |
+
'TealLexer': ('pip._vendor.pygments.lexers.teal', 'teal', ('teal',), ('*.teal',), ()),
|
| 525 |
+
'TeraTermLexer': ('pip._vendor.pygments.lexers.teraterm', 'Tera Term macro', ('teratermmacro', 'teraterm', 'ttl'), ('*.ttl',), ('text/x-teratermmacro',)),
|
| 526 |
+
'TermcapLexer': ('pip._vendor.pygments.lexers.configs', 'Termcap', ('termcap',), ('termcap', 'termcap.src'), ()),
|
| 527 |
+
'TerminfoLexer': ('pip._vendor.pygments.lexers.configs', 'Terminfo', ('terminfo',), ('terminfo', 'terminfo.src'), ()),
|
| 528 |
+
'TerraformLexer': ('pip._vendor.pygments.lexers.configs', 'Terraform', ('terraform', 'tf', 'hcl'), ('*.tf', '*.hcl'), ('application/x-tf', 'application/x-terraform')),
|
| 529 |
+
'TexLexer': ('pip._vendor.pygments.lexers.markup', 'TeX', ('tex', 'latex'), ('*.tex', '*.aux', '*.toc'), ('text/x-tex', 'text/x-latex')),
|
| 530 |
+
'TextLexer': ('pip._vendor.pygments.lexers.special', 'Text only', ('text',), ('*.txt',), ('text/plain',)),
|
| 531 |
+
'ThingsDBLexer': ('pip._vendor.pygments.lexers.thingsdb', 'ThingsDB', ('ti', 'thingsdb'), ('*.ti',), ()),
|
| 532 |
+
'ThriftLexer': ('pip._vendor.pygments.lexers.dsls', 'Thrift', ('thrift',), ('*.thrift',), ('application/x-thrift',)),
|
| 533 |
+
'TiddlyWiki5Lexer': ('pip._vendor.pygments.lexers.markup', 'tiddler', ('tid',), ('*.tid',), ('text/vnd.tiddlywiki',)),
|
| 534 |
+
'TlbLexer': ('pip._vendor.pygments.lexers.tlb', 'Tl-b', ('tlb',), ('*.tlb',), ()),
|
| 535 |
+
'TlsLexer': ('pip._vendor.pygments.lexers.tls', 'TLS Presentation Language', ('tls',), (), ()),
|
| 536 |
+
'TodotxtLexer': ('pip._vendor.pygments.lexers.textfmts', 'Todotxt', ('todotxt',), ('todo.txt', '*.todotxt'), ('text/x-todo',)),
|
| 537 |
+
'TransactSqlLexer': ('pip._vendor.pygments.lexers.sql', 'Transact-SQL', ('tsql', 't-sql'), ('*.sql',), ('text/x-tsql',)),
|
| 538 |
+
'TreetopLexer': ('pip._vendor.pygments.lexers.parsers', 'Treetop', ('treetop',), ('*.treetop', '*.tt'), ()),
|
| 539 |
+
'TsxLexer': ('pip._vendor.pygments.lexers.jsx', 'TSX', ('tsx',), ('*.tsx',), ('text/typescript-tsx',)),
|
| 540 |
+
'TurtleLexer': ('pip._vendor.pygments.lexers.rdf', 'Turtle', ('turtle',), ('*.ttl',), ('text/turtle', 'application/x-turtle')),
|
| 541 |
+
'TwigHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Twig', ('html+twig',), ('*.twig',), ('text/html+twig',)),
|
| 542 |
+
'TwigLexer': ('pip._vendor.pygments.lexers.templates', 'Twig', ('twig',), (), ('application/x-twig',)),
|
| 543 |
+
'TypeScriptLexer': ('pip._vendor.pygments.lexers.javascript', 'TypeScript', ('typescript', 'ts'), ('*.ts',), ('application/x-typescript', 'text/x-typescript')),
|
| 544 |
+
'TypoScriptCssDataLexer': ('pip._vendor.pygments.lexers.typoscript', 'TypoScriptCssData', ('typoscriptcssdata',), (), ()),
|
| 545 |
+
'TypoScriptHtmlDataLexer': ('pip._vendor.pygments.lexers.typoscript', 'TypoScriptHtmlData', ('typoscripthtmldata',), (), ()),
|
| 546 |
+
'TypoScriptLexer': ('pip._vendor.pygments.lexers.typoscript', 'TypoScript', ('typoscript',), ('*.typoscript',), ('text/x-typoscript',)),
|
| 547 |
+
'TypstLexer': ('pip._vendor.pygments.lexers.typst', 'Typst', ('typst',), ('*.typ',), ('text/x-typst',)),
|
| 548 |
+
'UL4Lexer': ('pip._vendor.pygments.lexers.ul4', 'UL4', ('ul4',), ('*.ul4',), ()),
|
| 549 |
+
'UcodeLexer': ('pip._vendor.pygments.lexers.unicon', 'ucode', ('ucode',), ('*.u', '*.u1', '*.u2'), ()),
|
| 550 |
+
'UniconLexer': ('pip._vendor.pygments.lexers.unicon', 'Unicon', ('unicon',), ('*.icn',), ('text/unicon',)),
|
| 551 |
+
'UnixConfigLexer': ('pip._vendor.pygments.lexers.configs', 'Unix/Linux config files', ('unixconfig', 'linuxconfig'), (), ()),
|
| 552 |
+
'UrbiscriptLexer': ('pip._vendor.pygments.lexers.urbi', 'UrbiScript', ('urbiscript',), ('*.u',), ('application/x-urbiscript',)),
|
| 553 |
+
'UrlEncodedLexer': ('pip._vendor.pygments.lexers.html', 'urlencoded', ('urlencoded',), (), ('application/x-www-form-urlencoded',)),
|
| 554 |
+
'UsdLexer': ('pip._vendor.pygments.lexers.usd', 'USD', ('usd', 'usda'), ('*.usd', '*.usda'), ()),
|
| 555 |
+
'VBScriptLexer': ('pip._vendor.pygments.lexers.basic', 'VBScript', ('vbscript',), ('*.vbs', '*.VBS'), ()),
|
| 556 |
+
'VCLLexer': ('pip._vendor.pygments.lexers.varnish', 'VCL', ('vcl',), ('*.vcl',), ('text/x-vclsrc',)),
|
| 557 |
+
'VCLSnippetLexer': ('pip._vendor.pygments.lexers.varnish', 'VCLSnippets', ('vclsnippets', 'vclsnippet'), (), ('text/x-vclsnippet',)),
|
| 558 |
+
'VCTreeStatusLexer': ('pip._vendor.pygments.lexers.console', 'VCTreeStatus', ('vctreestatus',), (), ()),
|
| 559 |
+
'VGLLexer': ('pip._vendor.pygments.lexers.dsls', 'VGL', ('vgl',), ('*.rpf',), ()),
|
| 560 |
+
'ValaLexer': ('pip._vendor.pygments.lexers.c_like', 'Vala', ('vala', 'vapi'), ('*.vala', '*.vapi'), ('text/x-vala',)),
|
| 561 |
+
'VbNetAspxLexer': ('pip._vendor.pygments.lexers.dotnet', 'aspx-vb', ('aspx-vb',), ('*.aspx', '*.asax', '*.ascx', '*.ashx', '*.asmx', '*.axd'), ()),
|
| 562 |
+
'VbNetLexer': ('pip._vendor.pygments.lexers.dotnet', 'VB.net', ('vb.net', 'vbnet', 'lobas', 'oobas', 'sobas', 'visual-basic', 'visualbasic'), ('*.vb', '*.bas'), ('text/x-vbnet', 'text/x-vba')),
|
| 563 |
+
'VelocityHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Velocity', ('html+velocity',), (), ('text/html+velocity',)),
|
| 564 |
+
'VelocityLexer': ('pip._vendor.pygments.lexers.templates', 'Velocity', ('velocity',), ('*.vm', '*.fhtml'), ()),
|
| 565 |
+
'VelocityXmlLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Velocity', ('xml+velocity',), (), ('application/xml+velocity',)),
|
| 566 |
+
'VerifpalLexer': ('pip._vendor.pygments.lexers.verifpal', 'Verifpal', ('verifpal',), ('*.vp',), ('text/x-verifpal',)),
|
| 567 |
+
'VerilogLexer': ('pip._vendor.pygments.lexers.hdl', 'verilog', ('verilog', 'v'), ('*.v',), ('text/x-verilog',)),
|
| 568 |
+
'VhdlLexer': ('pip._vendor.pygments.lexers.hdl', 'vhdl', ('vhdl',), ('*.vhdl', '*.vhd'), ('text/x-vhdl',)),
|
| 569 |
+
'VimLexer': ('pip._vendor.pygments.lexers.textedit', 'VimL', ('vim',), ('*.vim', '.vimrc', '.exrc', '.gvimrc', '_vimrc', '_exrc', '_gvimrc', 'vimrc', 'gvimrc'), ('text/x-vim',)),
|
| 570 |
+
'VisualPrologGrammarLexer': ('pip._vendor.pygments.lexers.vip', 'Visual Prolog Grammar', ('visualprologgrammar',), ('*.vipgrm',), ()),
|
| 571 |
+
'VisualPrologLexer': ('pip._vendor.pygments.lexers.vip', 'Visual Prolog', ('visualprolog',), ('*.pro', '*.cl', '*.i', '*.pack', '*.ph'), ()),
|
| 572 |
+
'VueLexer': ('pip._vendor.pygments.lexers.html', 'Vue', ('vue',), ('*.vue',), ()),
|
| 573 |
+
'VyperLexer': ('pip._vendor.pygments.lexers.vyper', 'Vyper', ('vyper',), ('*.vy',), ()),
|
| 574 |
+
'WDiffLexer': ('pip._vendor.pygments.lexers.diff', 'WDiff', ('wdiff',), ('*.wdiff',), ()),
|
| 575 |
+
'WatLexer': ('pip._vendor.pygments.lexers.webassembly', 'WebAssembly', ('wast', 'wat'), ('*.wat', '*.wast'), ()),
|
| 576 |
+
'WebIDLLexer': ('pip._vendor.pygments.lexers.webidl', 'Web IDL', ('webidl',), ('*.webidl',), ()),
|
| 577 |
+
'WgslLexer': ('pip._vendor.pygments.lexers.wgsl', 'WebGPU Shading Language', ('wgsl',), ('*.wgsl',), ('text/wgsl',)),
|
| 578 |
+
'WhileyLexer': ('pip._vendor.pygments.lexers.whiley', 'Whiley', ('whiley',), ('*.whiley',), ('text/x-whiley',)),
|
| 579 |
+
'WikitextLexer': ('pip._vendor.pygments.lexers.markup', 'Wikitext', ('wikitext', 'mediawiki'), (), ('text/x-wiki',)),
|
| 580 |
+
'WoWTocLexer': ('pip._vendor.pygments.lexers.wowtoc', 'World of Warcraft TOC', ('wowtoc',), ('*.toc',), ()),
|
| 581 |
+
'WrenLexer': ('pip._vendor.pygments.lexers.wren', 'Wren', ('wren',), ('*.wren',), ()),
|
| 582 |
+
'X10Lexer': ('pip._vendor.pygments.lexers.x10', 'X10', ('x10', 'xten'), ('*.x10',), ('text/x-x10',)),
|
| 583 |
+
'XMLUL4Lexer': ('pip._vendor.pygments.lexers.ul4', 'XML+UL4', ('xml+ul4',), ('*.xmlul4',), ()),
|
| 584 |
+
'XQueryLexer': ('pip._vendor.pygments.lexers.webmisc', 'XQuery', ('xquery', 'xqy', 'xq', 'xql', 'xqm'), ('*.xqy', '*.xquery', '*.xq', '*.xql', '*.xqm'), ('text/xquery', 'application/xquery')),
|
| 585 |
+
'XmlDjangoLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Django/Jinja', ('xml+django', 'xml+jinja'), ('*.xml.j2', '*.xml.jinja2'), ('application/xml+django', 'application/xml+jinja')),
|
| 586 |
+
'XmlErbLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Ruby', ('xml+ruby', 'xml+erb'), (), ('application/xml+ruby',)),
|
| 587 |
+
'XmlLexer': ('pip._vendor.pygments.lexers.html', 'XML', ('xml',), ('*.xml', '*.xsl', '*.rss', '*.xslt', '*.xsd', '*.wsdl', '*.wsf', '*.xbrl', '*.pom'), ('text/xml', 'application/xml', 'image/svg+xml', 'application/rss+xml', 'application/atom+xml')),
|
| 588 |
+
'XmlPhpLexer': ('pip._vendor.pygments.lexers.templates', 'XML+PHP', ('xml+php',), (), ('application/xml+php',)),
|
| 589 |
+
'XmlSmartyLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Smarty', ('xml+smarty',), (), ('application/xml+smarty',)),
|
| 590 |
+
'XorgLexer': ('pip._vendor.pygments.lexers.xorg', 'Xorg', ('xorg.conf',), ('xorg.conf',), ()),
|
| 591 |
+
'XppLexer': ('pip._vendor.pygments.lexers.dotnet', 'X++', ('xpp', 'x++'), ('*.xpp',), ()),
|
| 592 |
+
'XsltLexer': ('pip._vendor.pygments.lexers.html', 'XSLT', ('xslt',), ('*.xsl', '*.xslt', '*.xpl'), ('application/xsl+xml', 'application/xslt+xml')),
|
| 593 |
+
'XtendLexer': ('pip._vendor.pygments.lexers.jvm', 'Xtend', ('xtend',), ('*.xtend',), ('text/x-xtend',)),
|
| 594 |
+
'XtlangLexer': ('pip._vendor.pygments.lexers.lisp', 'xtlang', ('extempore',), ('*.xtm',), ()),
|
| 595 |
+
'YamlJinjaLexer': ('pip._vendor.pygments.lexers.templates', 'YAML+Jinja', ('yaml+jinja', 'salt', 'sls'), ('*.sls', '*.yaml.j2', '*.yml.j2', '*.yaml.jinja2', '*.yml.jinja2'), ('text/x-yaml+jinja', 'text/x-sls')),
|
| 596 |
+
'YamlLexer': ('pip._vendor.pygments.lexers.data', 'YAML', ('yaml',), ('*.yaml', '*.yml'), ('text/x-yaml',)),
|
| 597 |
+
'YangLexer': ('pip._vendor.pygments.lexers.yang', 'YANG', ('yang',), ('*.yang',), ('application/yang',)),
|
| 598 |
+
'YaraLexer': ('pip._vendor.pygments.lexers.yara', 'YARA', ('yara', 'yar'), ('*.yar',), ('text/x-yara',)),
|
| 599 |
+
'ZeekLexer': ('pip._vendor.pygments.lexers.dsls', 'Zeek', ('zeek', 'bro'), ('*.zeek', '*.bro'), ()),
|
| 600 |
+
'ZephirLexer': ('pip._vendor.pygments.lexers.php', 'Zephir', ('zephir',), ('*.zep',), ()),
|
| 601 |
+
'ZigLexer': ('pip._vendor.pygments.lexers.zig', 'Zig', ('zig',), ('*.zig',), ('text/zig',)),
|
| 602 |
+
'apdlexer': ('pip._vendor.pygments.lexers.apdlexer', 'ANSYS parametric design language', ('ansys', 'apdl'), ('*.ans',), ()),
|
| 603 |
+
}
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/lexers/python.py
ADDED
|
@@ -0,0 +1,1204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.lexers.python
|
| 3 |
+
~~~~~~~~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Lexers for Python and related languages.
|
| 6 |
+
|
| 7 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 8 |
+
:license: BSD, see LICENSE for details.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import keyword
|
| 12 |
+
|
| 13 |
+
from pip._vendor.pygments.lexer import DelegatingLexer, RegexLexer, include, \
|
| 14 |
+
bygroups, using, default, words, combined, this
|
| 15 |
+
from pip._vendor.pygments.util import get_bool_opt, shebang_matches
|
| 16 |
+
from pip._vendor.pygments.token import Text, Comment, Operator, Keyword, Name, String, \
|
| 17 |
+
Number, Punctuation, Generic, Other, Error, Whitespace
|
| 18 |
+
from pip._vendor.pygments import unistring as uni
|
| 19 |
+
|
| 20 |
+
__all__ = ['PythonLexer', 'PythonConsoleLexer', 'PythonTracebackLexer',
|
| 21 |
+
'Python2Lexer', 'Python2TracebackLexer',
|
| 22 |
+
'CythonLexer', 'DgLexer', 'NumPyLexer']
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class PythonLexer(RegexLexer):
|
| 26 |
+
"""
|
| 27 |
+
For Python source code (version 3.x).
|
| 28 |
+
|
| 29 |
+
.. versionchanged:: 2.5
|
| 30 |
+
This is now the default ``PythonLexer``. It is still available as the
|
| 31 |
+
alias ``Python3Lexer``.
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
name = 'Python'
|
| 35 |
+
url = 'https://www.python.org'
|
| 36 |
+
aliases = ['python', 'py', 'sage', 'python3', 'py3', 'bazel', 'starlark', 'pyi']
|
| 37 |
+
filenames = [
|
| 38 |
+
'*.py',
|
| 39 |
+
'*.pyw',
|
| 40 |
+
# Type stubs
|
| 41 |
+
'*.pyi',
|
| 42 |
+
# Jython
|
| 43 |
+
'*.jy',
|
| 44 |
+
# Sage
|
| 45 |
+
'*.sage',
|
| 46 |
+
# SCons
|
| 47 |
+
'*.sc',
|
| 48 |
+
'SConstruct',
|
| 49 |
+
'SConscript',
|
| 50 |
+
# Skylark/Starlark (used by Bazel, Buck, and Pants)
|
| 51 |
+
'*.bzl',
|
| 52 |
+
'BUCK',
|
| 53 |
+
'BUILD',
|
| 54 |
+
'BUILD.bazel',
|
| 55 |
+
'WORKSPACE',
|
| 56 |
+
# Twisted Application infrastructure
|
| 57 |
+
'*.tac',
|
| 58 |
+
# Execubot level format
|
| 59 |
+
'*.pye',
|
| 60 |
+
]
|
| 61 |
+
mimetypes = ['text/x-python', 'application/x-python',
|
| 62 |
+
'text/x-python3', 'application/x-python3']
|
| 63 |
+
version_added = '0.10'
|
| 64 |
+
|
| 65 |
+
uni_name = f"[{uni.xid_start}][{uni.xid_continue}]*"
|
| 66 |
+
|
| 67 |
+
def innerstring_rules(ttype):
|
| 68 |
+
return [
|
| 69 |
+
# the old style '%s' % (...) string formatting (still valid in Py3)
|
| 70 |
+
(r'%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?'
|
| 71 |
+
'[hlL]?[E-GXc-giorsaux%]', String.Interpol),
|
| 72 |
+
# the new style '{}'.format(...) string formatting
|
| 73 |
+
(r'\{'
|
| 74 |
+
r'((\w+)((\.\w+)|(\[[^\]]+\]))*)?' # field name
|
| 75 |
+
r'(\![sra])?' # conversion
|
| 76 |
+
r'(\:(.?[<>=\^])?[-+ ]?#?0?(\d+)?,?(\.\d+)?[E-GXb-gnosx%]?)?'
|
| 77 |
+
r'\}', String.Interpol),
|
| 78 |
+
|
| 79 |
+
# backslashes, quotes and formatting signs must be parsed one at a time
|
| 80 |
+
(r'[^\\\'"%{\n]+', ttype),
|
| 81 |
+
(r'[\'"\\]', ttype),
|
| 82 |
+
# unhandled string formatting sign
|
| 83 |
+
(r'%|(\{{1,2})', ttype)
|
| 84 |
+
# newlines are an error (use "nl" state)
|
| 85 |
+
]
|
| 86 |
+
|
| 87 |
+
def fstring_rules(ttype):
|
| 88 |
+
return [
|
| 89 |
+
# Assuming that a '}' is the closing brace after format specifier.
|
| 90 |
+
# Sadly, this means that we won't detect syntax error. But it's
|
| 91 |
+
# more important to parse correct syntax correctly, than to
|
| 92 |
+
# highlight invalid syntax.
|
| 93 |
+
(r'\}', String.Interpol),
|
| 94 |
+
(r'\{', String.Interpol, 'expr-inside-fstring'),
|
| 95 |
+
# backslashes, quotes and formatting signs must be parsed one at a time
|
| 96 |
+
(r'[^\\\'"{}\n]+', ttype),
|
| 97 |
+
(r'[\'"\\]', ttype),
|
| 98 |
+
# newlines are an error (use "nl" state)
|
| 99 |
+
]
|
| 100 |
+
|
| 101 |
+
tokens = {
|
| 102 |
+
'root': [
|
| 103 |
+
(r'\n', Whitespace),
|
| 104 |
+
(r'^(\s*)([rRuUbB]{,2})("""(?:.|\n)*?""")',
|
| 105 |
+
bygroups(Whitespace, String.Affix, String.Doc)),
|
| 106 |
+
(r"^(\s*)([rRuUbB]{,2})('''(?:.|\n)*?''')",
|
| 107 |
+
bygroups(Whitespace, String.Affix, String.Doc)),
|
| 108 |
+
(r'\A#!.+$', Comment.Hashbang),
|
| 109 |
+
(r'#.*$', Comment.Single),
|
| 110 |
+
(r'\\\n', Text),
|
| 111 |
+
(r'\\', Text),
|
| 112 |
+
include('keywords'),
|
| 113 |
+
include('soft-keywords'),
|
| 114 |
+
(r'(def)((?:\s|\\\s)+)', bygroups(Keyword, Whitespace), 'funcname'),
|
| 115 |
+
(r'(class)((?:\s|\\\s)+)', bygroups(Keyword, Whitespace), 'classname'),
|
| 116 |
+
(r'(from)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Whitespace),
|
| 117 |
+
'fromimport'),
|
| 118 |
+
(r'(import)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Whitespace),
|
| 119 |
+
'import'),
|
| 120 |
+
include('expr'),
|
| 121 |
+
],
|
| 122 |
+
'expr': [
|
| 123 |
+
# raw f-strings and t-strings
|
| 124 |
+
('(?i)(r[ft]|[ft]r)(""")',
|
| 125 |
+
bygroups(String.Affix, String.Double),
|
| 126 |
+
combined('rfstringescape', 'tdqf')),
|
| 127 |
+
("(?i)(r[ft]|[ft]r)(''')",
|
| 128 |
+
bygroups(String.Affix, String.Single),
|
| 129 |
+
combined('rfstringescape', 'tsqf')),
|
| 130 |
+
('(?i)(r[ft]|[ft]r)(")',
|
| 131 |
+
bygroups(String.Affix, String.Double),
|
| 132 |
+
combined('rfstringescape', 'dqf')),
|
| 133 |
+
("(?i)(r[ft]|[ft]r)(')",
|
| 134 |
+
bygroups(String.Affix, String.Single),
|
| 135 |
+
combined('rfstringescape', 'sqf')),
|
| 136 |
+
# non-raw f-strings and t-strings
|
| 137 |
+
('([fFtT])(""")', bygroups(String.Affix, String.Double),
|
| 138 |
+
combined('fstringescape', 'tdqf')),
|
| 139 |
+
("([fFtT])(''')", bygroups(String.Affix, String.Single),
|
| 140 |
+
combined('fstringescape', 'tsqf')),
|
| 141 |
+
('([fFtT])(")', bygroups(String.Affix, String.Double),
|
| 142 |
+
combined('fstringescape', 'dqf')),
|
| 143 |
+
("([fFtT])(')", bygroups(String.Affix, String.Single),
|
| 144 |
+
combined('fstringescape', 'sqf')),
|
| 145 |
+
# raw bytes and strings
|
| 146 |
+
('(?i)(rb|br|r)(""")',
|
| 147 |
+
bygroups(String.Affix, String.Double), 'tdqs'),
|
| 148 |
+
("(?i)(rb|br|r)(''')",
|
| 149 |
+
bygroups(String.Affix, String.Single), 'tsqs'),
|
| 150 |
+
('(?i)(rb|br|r)(")',
|
| 151 |
+
bygroups(String.Affix, String.Double), 'dqs'),
|
| 152 |
+
("(?i)(rb|br|r)(')",
|
| 153 |
+
bygroups(String.Affix, String.Single), 'sqs'),
|
| 154 |
+
# non-raw strings
|
| 155 |
+
('([uU]?)(""")', bygroups(String.Affix, String.Double),
|
| 156 |
+
combined('stringescape', 'tdqs')),
|
| 157 |
+
("([uU]?)(''')", bygroups(String.Affix, String.Single),
|
| 158 |
+
combined('stringescape', 'tsqs')),
|
| 159 |
+
('([uU]?)(")', bygroups(String.Affix, String.Double),
|
| 160 |
+
combined('stringescape', 'dqs')),
|
| 161 |
+
("([uU]?)(')", bygroups(String.Affix, String.Single),
|
| 162 |
+
combined('stringescape', 'sqs')),
|
| 163 |
+
# non-raw bytes
|
| 164 |
+
('([bB])(""")', bygroups(String.Affix, String.Double),
|
| 165 |
+
combined('bytesescape', 'tdqs')),
|
| 166 |
+
("([bB])(''')", bygroups(String.Affix, String.Single),
|
| 167 |
+
combined('bytesescape', 'tsqs')),
|
| 168 |
+
('([bB])(")', bygroups(String.Affix, String.Double),
|
| 169 |
+
combined('bytesescape', 'dqs')),
|
| 170 |
+
("([bB])(')", bygroups(String.Affix, String.Single),
|
| 171 |
+
combined('bytesescape', 'sqs')),
|
| 172 |
+
|
| 173 |
+
(r'[^\S\n]+', Text),
|
| 174 |
+
include('numbers'),
|
| 175 |
+
(r'!=|==|<<|>>|:=|[-~+/*%=<>&^|.]', Operator),
|
| 176 |
+
(r'[]{}:(),;[]', Punctuation),
|
| 177 |
+
(r'(in|is|and|or|not)\b', Operator.Word),
|
| 178 |
+
include('expr-keywords'),
|
| 179 |
+
include('builtins'),
|
| 180 |
+
include('magicfuncs'),
|
| 181 |
+
include('magicvars'),
|
| 182 |
+
include('name'),
|
| 183 |
+
],
|
| 184 |
+
'expr-inside-fstring': [
|
| 185 |
+
(r'[{([]', Punctuation, 'expr-inside-fstring-inner'),
|
| 186 |
+
# without format specifier
|
| 187 |
+
(r'(=\s*)?' # debug (https://bugs.python.org/issue36817)
|
| 188 |
+
r'(\![sraf])?' # conversion
|
| 189 |
+
r'\}', String.Interpol, '#pop'),
|
| 190 |
+
# with format specifier
|
| 191 |
+
# we'll catch the remaining '}' in the outer scope
|
| 192 |
+
(r'(=\s*)?' # debug (https://bugs.python.org/issue36817)
|
| 193 |
+
r'(\![sraf])?' # conversion
|
| 194 |
+
r':', String.Interpol, '#pop'),
|
| 195 |
+
(r'\s+', Whitespace), # allow new lines
|
| 196 |
+
include('expr'),
|
| 197 |
+
],
|
| 198 |
+
'expr-inside-fstring-inner': [
|
| 199 |
+
(r'[{([]', Punctuation, 'expr-inside-fstring-inner'),
|
| 200 |
+
(r'[])}]', Punctuation, '#pop'),
|
| 201 |
+
(r'\s+', Whitespace), # allow new lines
|
| 202 |
+
include('expr'),
|
| 203 |
+
],
|
| 204 |
+
'expr-keywords': [
|
| 205 |
+
# Based on https://docs.python.org/3/reference/expressions.html
|
| 206 |
+
(words((
|
| 207 |
+
'async for', 'await', 'else', 'for', 'if', 'lambda',
|
| 208 |
+
'yield', 'yield from'), suffix=r'\b'),
|
| 209 |
+
Keyword),
|
| 210 |
+
(words(('True', 'False', 'None'), suffix=r'\b'), Keyword.Constant),
|
| 211 |
+
],
|
| 212 |
+
'keywords': [
|
| 213 |
+
(words((
|
| 214 |
+
'assert', 'async', 'await', 'break', 'continue', 'del', 'elif',
|
| 215 |
+
'else', 'except', 'finally', 'for', 'global', 'if', 'lambda',
|
| 216 |
+
'pass', 'raise', 'nonlocal', 'return', 'try', 'while', 'yield',
|
| 217 |
+
'yield from', 'as', 'with'), suffix=r'\b'),
|
| 218 |
+
Keyword),
|
| 219 |
+
(words(('True', 'False', 'None'), suffix=r'\b'), Keyword.Constant),
|
| 220 |
+
],
|
| 221 |
+
'soft-keywords': [
|
| 222 |
+
# `match`, `case` and `_` soft keywords
|
| 223 |
+
(r'(^[ \t]*)' # at beginning of line + possible indentation
|
| 224 |
+
r'(match|case)\b' # a possible keyword
|
| 225 |
+
r'(?![ \t]*(?:' # not followed by...
|
| 226 |
+
r'[:,;=^&|@~)\]}]|(?:' + # characters and keywords that mean this isn't
|
| 227 |
+
# pattern matching (but None/True/False is ok)
|
| 228 |
+
r'|'.join(k for k in keyword.kwlist if k[0].islower()) + r')\b))',
|
| 229 |
+
bygroups(Text, Keyword), 'soft-keywords-inner'),
|
| 230 |
+
],
|
| 231 |
+
'soft-keywords-inner': [
|
| 232 |
+
# optional `_` keyword
|
| 233 |
+
(r'(\s+)([^\n_]*)(_\b)', bygroups(Whitespace, using(this), Keyword)),
|
| 234 |
+
default('#pop')
|
| 235 |
+
],
|
| 236 |
+
'builtins': [
|
| 237 |
+
(words((
|
| 238 |
+
'__import__', 'abs', 'aiter', 'all', 'any', 'bin', 'bool', 'bytearray',
|
| 239 |
+
'breakpoint', 'bytes', 'callable', 'chr', 'classmethod', 'compile',
|
| 240 |
+
'complex', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval',
|
| 241 |
+
'filter', 'float', 'format', 'frozenset', 'getattr', 'globals',
|
| 242 |
+
'hasattr', 'hash', 'hex', 'id', 'input', 'int', 'isinstance',
|
| 243 |
+
'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max',
|
| 244 |
+
'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow',
|
| 245 |
+
'print', 'property', 'range', 'repr', 'reversed', 'round', 'set',
|
| 246 |
+
'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super',
|
| 247 |
+
'tuple', 'type', 'vars', 'zip'), prefix=r'(?<!\.)', suffix=r'\b'),
|
| 248 |
+
Name.Builtin),
|
| 249 |
+
(r'(?<!\.)(self|Ellipsis|NotImplemented|cls)\b', Name.Builtin.Pseudo),
|
| 250 |
+
(words((
|
| 251 |
+
'ArithmeticError', 'AssertionError', 'AttributeError',
|
| 252 |
+
'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning',
|
| 253 |
+
'EOFError', 'EnvironmentError', 'Exception', 'FloatingPointError',
|
| 254 |
+
'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError',
|
| 255 |
+
'ImportWarning', 'IndentationError', 'IndexError', 'KeyError',
|
| 256 |
+
'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError',
|
| 257 |
+
'NotImplementedError', 'OSError', 'OverflowError',
|
| 258 |
+
'PendingDeprecationWarning', 'ReferenceError', 'ResourceWarning',
|
| 259 |
+
'RuntimeError', 'RuntimeWarning', 'StopIteration',
|
| 260 |
+
'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit',
|
| 261 |
+
'TabError', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError',
|
| 262 |
+
'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError',
|
| 263 |
+
'UnicodeWarning', 'UserWarning', 'ValueError', 'VMSError',
|
| 264 |
+
'Warning', 'WindowsError', 'ZeroDivisionError',
|
| 265 |
+
# new builtin exceptions from PEP 3151
|
| 266 |
+
'BlockingIOError', 'ChildProcessError', 'ConnectionError',
|
| 267 |
+
'BrokenPipeError', 'ConnectionAbortedError', 'ConnectionRefusedError',
|
| 268 |
+
'ConnectionResetError', 'FileExistsError', 'FileNotFoundError',
|
| 269 |
+
'InterruptedError', 'IsADirectoryError', 'NotADirectoryError',
|
| 270 |
+
'PermissionError', 'ProcessLookupError', 'TimeoutError',
|
| 271 |
+
# others new in Python 3
|
| 272 |
+
'StopAsyncIteration', 'ModuleNotFoundError', 'RecursionError',
|
| 273 |
+
'EncodingWarning'),
|
| 274 |
+
prefix=r'(?<!\.)', suffix=r'\b'),
|
| 275 |
+
Name.Exception),
|
| 276 |
+
],
|
| 277 |
+
'magicfuncs': [
|
| 278 |
+
(words((
|
| 279 |
+
'__abs__', '__add__', '__aenter__', '__aexit__', '__aiter__',
|
| 280 |
+
'__and__', '__anext__', '__await__', '__bool__', '__bytes__',
|
| 281 |
+
'__call__', '__complex__', '__contains__', '__del__', '__delattr__',
|
| 282 |
+
'__delete__', '__delitem__', '__dir__', '__divmod__', '__enter__',
|
| 283 |
+
'__eq__', '__exit__', '__float__', '__floordiv__', '__format__',
|
| 284 |
+
'__ge__', '__get__', '__getattr__', '__getattribute__',
|
| 285 |
+
'__getitem__', '__gt__', '__hash__', '__iadd__', '__iand__',
|
| 286 |
+
'__ifloordiv__', '__ilshift__', '__imatmul__', '__imod__',
|
| 287 |
+
'__imul__', '__index__', '__init__', '__instancecheck__',
|
| 288 |
+
'__int__', '__invert__', '__ior__', '__ipow__', '__irshift__',
|
| 289 |
+
'__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__',
|
| 290 |
+
'__len__', '__length_hint__', '__lshift__', '__lt__', '__matmul__',
|
| 291 |
+
'__missing__', '__mod__', '__mul__', '__ne__', '__neg__',
|
| 292 |
+
'__new__', '__next__', '__or__', '__pos__', '__pow__',
|
| 293 |
+
'__prepare__', '__radd__', '__rand__', '__rdivmod__', '__repr__',
|
| 294 |
+
'__reversed__', '__rfloordiv__', '__rlshift__', '__rmatmul__',
|
| 295 |
+
'__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__',
|
| 296 |
+
'__rrshift__', '__rshift__', '__rsub__', '__rtruediv__',
|
| 297 |
+
'__rxor__', '__set__', '__setattr__', '__setitem__', '__str__',
|
| 298 |
+
'__sub__', '__subclasscheck__', '__truediv__',
|
| 299 |
+
'__xor__'), suffix=r'\b'),
|
| 300 |
+
Name.Function.Magic),
|
| 301 |
+
],
|
| 302 |
+
'magicvars': [
|
| 303 |
+
(words((
|
| 304 |
+
'__annotations__', '__bases__', '__class__', '__closure__',
|
| 305 |
+
'__code__', '__defaults__', '__dict__', '__doc__', '__file__',
|
| 306 |
+
'__func__', '__globals__', '__kwdefaults__', '__module__',
|
| 307 |
+
'__mro__', '__name__', '__objclass__', '__qualname__',
|
| 308 |
+
'__self__', '__slots__', '__weakref__'), suffix=r'\b'),
|
| 309 |
+
Name.Variable.Magic),
|
| 310 |
+
],
|
| 311 |
+
'numbers': [
|
| 312 |
+
(r'(\d(?:_?\d)*\.(?:\d(?:_?\d)*)?|(?:\d(?:_?\d)*)?\.\d(?:_?\d)*)'
|
| 313 |
+
r'([eE][+-]?\d(?:_?\d)*)?', Number.Float),
|
| 314 |
+
(r'\d(?:_?\d)*[eE][+-]?\d(?:_?\d)*j?', Number.Float),
|
| 315 |
+
(r'0[oO](?:_?[0-7])+', Number.Oct),
|
| 316 |
+
(r'0[bB](?:_?[01])+', Number.Bin),
|
| 317 |
+
(r'0[xX](?:_?[a-fA-F0-9])+', Number.Hex),
|
| 318 |
+
(r'\d(?:_?\d)*', Number.Integer),
|
| 319 |
+
],
|
| 320 |
+
'name': [
|
| 321 |
+
(r'@' + uni_name, Name.Decorator),
|
| 322 |
+
(r'@', Operator), # new matrix multiplication operator
|
| 323 |
+
(uni_name, Name),
|
| 324 |
+
],
|
| 325 |
+
'funcname': [
|
| 326 |
+
include('magicfuncs'),
|
| 327 |
+
(uni_name, Name.Function, '#pop'),
|
| 328 |
+
default('#pop'),
|
| 329 |
+
],
|
| 330 |
+
'classname': [
|
| 331 |
+
(uni_name, Name.Class, '#pop'),
|
| 332 |
+
],
|
| 333 |
+
'import': [
|
| 334 |
+
(r'(\s+)(as)(\s+)', bygroups(Whitespace, Keyword, Whitespace)),
|
| 335 |
+
(r'\.', Name.Namespace),
|
| 336 |
+
(uni_name, Name.Namespace),
|
| 337 |
+
(r'(\s*)(,)(\s*)', bygroups(Whitespace, Operator, Whitespace)),
|
| 338 |
+
default('#pop') # all else: go back
|
| 339 |
+
],
|
| 340 |
+
'fromimport': [
|
| 341 |
+
(r'(\s+)(import)\b', bygroups(Whitespace, Keyword.Namespace), '#pop'),
|
| 342 |
+
(r'\.', Name.Namespace),
|
| 343 |
+
# if None occurs here, it's "raise x from None", since None can
|
| 344 |
+
# never be a module name
|
| 345 |
+
(r'None\b', Keyword.Constant, '#pop'),
|
| 346 |
+
(uni_name, Name.Namespace),
|
| 347 |
+
default('#pop'),
|
| 348 |
+
],
|
| 349 |
+
'rfstringescape': [
|
| 350 |
+
(r'\{\{', String.Escape),
|
| 351 |
+
(r'\}\}', String.Escape),
|
| 352 |
+
],
|
| 353 |
+
'fstringescape': [
|
| 354 |
+
include('rfstringescape'),
|
| 355 |
+
include('stringescape'),
|
| 356 |
+
],
|
| 357 |
+
'bytesescape': [
|
| 358 |
+
(r'\\([\\abfnrtv"\']|\n|x[a-fA-F0-9]{2}|[0-7]{1,3})', String.Escape)
|
| 359 |
+
],
|
| 360 |
+
'stringescape': [
|
| 361 |
+
(r'\\(N\{.*?\}|u[a-fA-F0-9]{4}|U[a-fA-F0-9]{8})', String.Escape),
|
| 362 |
+
include('bytesescape')
|
| 363 |
+
],
|
| 364 |
+
'fstrings-single': fstring_rules(String.Single),
|
| 365 |
+
'fstrings-double': fstring_rules(String.Double),
|
| 366 |
+
'strings-single': innerstring_rules(String.Single),
|
| 367 |
+
'strings-double': innerstring_rules(String.Double),
|
| 368 |
+
'dqf': [
|
| 369 |
+
(r'"', String.Double, '#pop'),
|
| 370 |
+
(r'\\\\|\\"|\\\n', String.Escape), # included here for raw strings
|
| 371 |
+
include('fstrings-double')
|
| 372 |
+
],
|
| 373 |
+
'sqf': [
|
| 374 |
+
(r"'", String.Single, '#pop'),
|
| 375 |
+
(r"\\\\|\\'|\\\n", String.Escape), # included here for raw strings
|
| 376 |
+
include('fstrings-single')
|
| 377 |
+
],
|
| 378 |
+
'dqs': [
|
| 379 |
+
(r'"', String.Double, '#pop'),
|
| 380 |
+
(r'\\\\|\\"|\\\n', String.Escape), # included here for raw strings
|
| 381 |
+
include('strings-double')
|
| 382 |
+
],
|
| 383 |
+
'sqs': [
|
| 384 |
+
(r"'", String.Single, '#pop'),
|
| 385 |
+
(r"\\\\|\\'|\\\n", String.Escape), # included here for raw strings
|
| 386 |
+
include('strings-single')
|
| 387 |
+
],
|
| 388 |
+
'tdqf': [
|
| 389 |
+
(r'"""', String.Double, '#pop'),
|
| 390 |
+
include('fstrings-double'),
|
| 391 |
+
(r'\n', String.Double)
|
| 392 |
+
],
|
| 393 |
+
'tsqf': [
|
| 394 |
+
(r"'''", String.Single, '#pop'),
|
| 395 |
+
include('fstrings-single'),
|
| 396 |
+
(r'\n', String.Single)
|
| 397 |
+
],
|
| 398 |
+
'tdqs': [
|
| 399 |
+
(r'"""', String.Double, '#pop'),
|
| 400 |
+
include('strings-double'),
|
| 401 |
+
(r'\n', String.Double)
|
| 402 |
+
],
|
| 403 |
+
'tsqs': [
|
| 404 |
+
(r"'''", String.Single, '#pop'),
|
| 405 |
+
include('strings-single'),
|
| 406 |
+
(r'\n', String.Single)
|
| 407 |
+
],
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
def analyse_text(text):
|
| 411 |
+
return shebang_matches(text, r'pythonw?(3(\.\d)?)?') or \
|
| 412 |
+
'import ' in text[:1000]
|
| 413 |
+
|
| 414 |
+
|
| 415 |
+
Python3Lexer = PythonLexer
|
| 416 |
+
|
| 417 |
+
|
| 418 |
+
class Python2Lexer(RegexLexer):
|
| 419 |
+
"""
|
| 420 |
+
For Python 2.x source code.
|
| 421 |
+
|
| 422 |
+
.. versionchanged:: 2.5
|
| 423 |
+
This class has been renamed from ``PythonLexer``. ``PythonLexer`` now
|
| 424 |
+
refers to the Python 3 variant. File name patterns like ``*.py`` have
|
| 425 |
+
been moved to Python 3 as well.
|
| 426 |
+
"""
|
| 427 |
+
|
| 428 |
+
name = 'Python 2.x'
|
| 429 |
+
url = 'https://www.python.org'
|
| 430 |
+
aliases = ['python2', 'py2']
|
| 431 |
+
filenames = [] # now taken over by PythonLexer (3.x)
|
| 432 |
+
mimetypes = ['text/x-python2', 'application/x-python2']
|
| 433 |
+
version_added = ''
|
| 434 |
+
|
| 435 |
+
def innerstring_rules(ttype):
|
| 436 |
+
return [
|
| 437 |
+
# the old style '%s' % (...) string formatting
|
| 438 |
+
(r'%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?'
|
| 439 |
+
'[hlL]?[E-GXc-giorsux%]', String.Interpol),
|
| 440 |
+
# backslashes, quotes and formatting signs must be parsed one at a time
|
| 441 |
+
(r'[^\\\'"%\n]+', ttype),
|
| 442 |
+
(r'[\'"\\]', ttype),
|
| 443 |
+
# unhandled string formatting sign
|
| 444 |
+
(r'%', ttype),
|
| 445 |
+
# newlines are an error (use "nl" state)
|
| 446 |
+
]
|
| 447 |
+
|
| 448 |
+
tokens = {
|
| 449 |
+
'root': [
|
| 450 |
+
(r'\n', Whitespace),
|
| 451 |
+
(r'^(\s*)([rRuUbB]{,2})("""(?:.|\n)*?""")',
|
| 452 |
+
bygroups(Whitespace, String.Affix, String.Doc)),
|
| 453 |
+
(r"^(\s*)([rRuUbB]{,2})('''(?:.|\n)*?''')",
|
| 454 |
+
bygroups(Whitespace, String.Affix, String.Doc)),
|
| 455 |
+
(r'[^\S\n]+', Text),
|
| 456 |
+
(r'\A#!.+$', Comment.Hashbang),
|
| 457 |
+
(r'#.*$', Comment.Single),
|
| 458 |
+
(r'[]{}:(),;[]', Punctuation),
|
| 459 |
+
(r'\\\n', Text),
|
| 460 |
+
(r'\\', Text),
|
| 461 |
+
(r'(in|is|and|or|not)\b', Operator.Word),
|
| 462 |
+
(r'!=|==|<<|>>|[-~+/*%=<>&^|.]', Operator),
|
| 463 |
+
include('keywords'),
|
| 464 |
+
(r'(def)((?:\s|\\\s)+)', bygroups(Keyword, Whitespace), 'funcname'),
|
| 465 |
+
(r'(class)((?:\s|\\\s)+)', bygroups(Keyword, Whitespace), 'classname'),
|
| 466 |
+
(r'(from)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Whitespace),
|
| 467 |
+
'fromimport'),
|
| 468 |
+
(r'(import)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Whitespace),
|
| 469 |
+
'import'),
|
| 470 |
+
include('builtins'),
|
| 471 |
+
include('magicfuncs'),
|
| 472 |
+
include('magicvars'),
|
| 473 |
+
include('backtick'),
|
| 474 |
+
('([rR]|[uUbB][rR]|[rR][uUbB])(""")',
|
| 475 |
+
bygroups(String.Affix, String.Double), 'tdqs'),
|
| 476 |
+
("([rR]|[uUbB][rR]|[rR][uUbB])(''')",
|
| 477 |
+
bygroups(String.Affix, String.Single), 'tsqs'),
|
| 478 |
+
('([rR]|[uUbB][rR]|[rR][uUbB])(")',
|
| 479 |
+
bygroups(String.Affix, String.Double), 'dqs'),
|
| 480 |
+
("([rR]|[uUbB][rR]|[rR][uUbB])(')",
|
| 481 |
+
bygroups(String.Affix, String.Single), 'sqs'),
|
| 482 |
+
('([uUbB]?)(""")', bygroups(String.Affix, String.Double),
|
| 483 |
+
combined('stringescape', 'tdqs')),
|
| 484 |
+
("([uUbB]?)(''')", bygroups(String.Affix, String.Single),
|
| 485 |
+
combined('stringescape', 'tsqs')),
|
| 486 |
+
('([uUbB]?)(")', bygroups(String.Affix, String.Double),
|
| 487 |
+
combined('stringescape', 'dqs')),
|
| 488 |
+
("([uUbB]?)(')", bygroups(String.Affix, String.Single),
|
| 489 |
+
combined('stringescape', 'sqs')),
|
| 490 |
+
include('name'),
|
| 491 |
+
include('numbers'),
|
| 492 |
+
],
|
| 493 |
+
'keywords': [
|
| 494 |
+
(words((
|
| 495 |
+
'assert', 'break', 'continue', 'del', 'elif', 'else', 'except',
|
| 496 |
+
'exec', 'finally', 'for', 'global', 'if', 'lambda', 'pass',
|
| 497 |
+
'print', 'raise', 'return', 'try', 'while', 'yield',
|
| 498 |
+
'yield from', 'as', 'with'), suffix=r'\b'),
|
| 499 |
+
Keyword),
|
| 500 |
+
],
|
| 501 |
+
'builtins': [
|
| 502 |
+
(words((
|
| 503 |
+
'__import__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin',
|
| 504 |
+
'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod',
|
| 505 |
+
'cmp', 'coerce', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
|
| 506 |
+
'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float',
|
| 507 |
+
'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'hex', 'id',
|
| 508 |
+
'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len',
|
| 509 |
+
'list', 'locals', 'long', 'map', 'max', 'min', 'next', 'object',
|
| 510 |
+
'oct', 'open', 'ord', 'pow', 'property', 'range', 'raw_input', 'reduce',
|
| 511 |
+
'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
|
| 512 |
+
'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type',
|
| 513 |
+
'unichr', 'unicode', 'vars', 'xrange', 'zip'),
|
| 514 |
+
prefix=r'(?<!\.)', suffix=r'\b'),
|
| 515 |
+
Name.Builtin),
|
| 516 |
+
(r'(?<!\.)(self|None|Ellipsis|NotImplemented|False|True|cls'
|
| 517 |
+
r')\b', Name.Builtin.Pseudo),
|
| 518 |
+
(words((
|
| 519 |
+
'ArithmeticError', 'AssertionError', 'AttributeError',
|
| 520 |
+
'BaseException', 'DeprecationWarning', 'EOFError', 'EnvironmentError',
|
| 521 |
+
'Exception', 'FloatingPointError', 'FutureWarning', 'GeneratorExit',
|
| 522 |
+
'IOError', 'ImportError', 'ImportWarning', 'IndentationError',
|
| 523 |
+
'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError',
|
| 524 |
+
'MemoryError', 'NameError',
|
| 525 |
+
'NotImplementedError', 'OSError', 'OverflowError', 'OverflowWarning',
|
| 526 |
+
'PendingDeprecationWarning', 'ReferenceError',
|
| 527 |
+
'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration',
|
| 528 |
+
'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit',
|
| 529 |
+
'TabError', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError',
|
| 530 |
+
'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError',
|
| 531 |
+
'UnicodeWarning', 'UserWarning', 'ValueError', 'VMSError', 'Warning',
|
| 532 |
+
'WindowsError', 'ZeroDivisionError'), prefix=r'(?<!\.)', suffix=r'\b'),
|
| 533 |
+
Name.Exception),
|
| 534 |
+
],
|
| 535 |
+
'magicfuncs': [
|
| 536 |
+
(words((
|
| 537 |
+
'__abs__', '__add__', '__and__', '__call__', '__cmp__', '__coerce__',
|
| 538 |
+
'__complex__', '__contains__', '__del__', '__delattr__', '__delete__',
|
| 539 |
+
'__delitem__', '__delslice__', '__div__', '__divmod__', '__enter__',
|
| 540 |
+
'__eq__', '__exit__', '__float__', '__floordiv__', '__ge__', '__get__',
|
| 541 |
+
'__getattr__', '__getattribute__', '__getitem__', '__getslice__', '__gt__',
|
| 542 |
+
'__hash__', '__hex__', '__iadd__', '__iand__', '__idiv__', '__ifloordiv__',
|
| 543 |
+
'__ilshift__', '__imod__', '__imul__', '__index__', '__init__',
|
| 544 |
+
'__instancecheck__', '__int__', '__invert__', '__iop__', '__ior__',
|
| 545 |
+
'__ipow__', '__irshift__', '__isub__', '__iter__', '__itruediv__',
|
| 546 |
+
'__ixor__', '__le__', '__len__', '__long__', '__lshift__', '__lt__',
|
| 547 |
+
'__missing__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__',
|
| 548 |
+
'__nonzero__', '__oct__', '__op__', '__or__', '__pos__', '__pow__',
|
| 549 |
+
'__radd__', '__rand__', '__rcmp__', '__rdiv__', '__rdivmod__', '__repr__',
|
| 550 |
+
'__reversed__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__',
|
| 551 |
+
'__rop__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__',
|
| 552 |
+
'__rtruediv__', '__rxor__', '__set__', '__setattr__', '__setitem__',
|
| 553 |
+
'__setslice__', '__str__', '__sub__', '__subclasscheck__', '__truediv__',
|
| 554 |
+
'__unicode__', '__xor__'), suffix=r'\b'),
|
| 555 |
+
Name.Function.Magic),
|
| 556 |
+
],
|
| 557 |
+
'magicvars': [
|
| 558 |
+
(words((
|
| 559 |
+
'__bases__', '__class__', '__closure__', '__code__', '__defaults__',
|
| 560 |
+
'__dict__', '__doc__', '__file__', '__func__', '__globals__',
|
| 561 |
+
'__metaclass__', '__module__', '__mro__', '__name__', '__self__',
|
| 562 |
+
'__slots__', '__weakref__'),
|
| 563 |
+
suffix=r'\b'),
|
| 564 |
+
Name.Variable.Magic),
|
| 565 |
+
],
|
| 566 |
+
'numbers': [
|
| 567 |
+
(r'(\d+\.\d*|\d*\.\d+)([eE][+-]?[0-9]+)?j?', Number.Float),
|
| 568 |
+
(r'\d+[eE][+-]?[0-9]+j?', Number.Float),
|
| 569 |
+
(r'0[0-7]+j?', Number.Oct),
|
| 570 |
+
(r'0[bB][01]+', Number.Bin),
|
| 571 |
+
(r'0[xX][a-fA-F0-9]+', Number.Hex),
|
| 572 |
+
(r'\d+L', Number.Integer.Long),
|
| 573 |
+
(r'\d+j?', Number.Integer)
|
| 574 |
+
],
|
| 575 |
+
'backtick': [
|
| 576 |
+
('`.*?`', String.Backtick),
|
| 577 |
+
],
|
| 578 |
+
'name': [
|
| 579 |
+
(r'@[\w.]+', Name.Decorator),
|
| 580 |
+
(r'[a-zA-Z_]\w*', Name),
|
| 581 |
+
],
|
| 582 |
+
'funcname': [
|
| 583 |
+
include('magicfuncs'),
|
| 584 |
+
(r'[a-zA-Z_]\w*', Name.Function, '#pop'),
|
| 585 |
+
default('#pop'),
|
| 586 |
+
],
|
| 587 |
+
'classname': [
|
| 588 |
+
(r'[a-zA-Z_]\w*', Name.Class, '#pop')
|
| 589 |
+
],
|
| 590 |
+
'import': [
|
| 591 |
+
(r'(?:[ \t]|\\\n)+', Text),
|
| 592 |
+
(r'as\b', Keyword.Namespace),
|
| 593 |
+
(r',', Operator),
|
| 594 |
+
(r'[a-zA-Z_][\w.]*', Name.Namespace),
|
| 595 |
+
default('#pop') # all else: go back
|
| 596 |
+
],
|
| 597 |
+
'fromimport': [
|
| 598 |
+
(r'(?:[ \t]|\\\n)+', Text),
|
| 599 |
+
(r'import\b', Keyword.Namespace, '#pop'),
|
| 600 |
+
# if None occurs here, it's "raise x from None", since None can
|
| 601 |
+
# never be a module name
|
| 602 |
+
(r'None\b', Name.Builtin.Pseudo, '#pop'),
|
| 603 |
+
# sadly, in "raise x from y" y will be highlighted as namespace too
|
| 604 |
+
(r'[a-zA-Z_.][\w.]*', Name.Namespace),
|
| 605 |
+
# anything else here also means "raise x from y" and is therefore
|
| 606 |
+
# not an error
|
| 607 |
+
default('#pop'),
|
| 608 |
+
],
|
| 609 |
+
'stringescape': [
|
| 610 |
+
(r'\\([\\abfnrtv"\']|\n|N\{.*?\}|u[a-fA-F0-9]{4}|'
|
| 611 |
+
r'U[a-fA-F0-9]{8}|x[a-fA-F0-9]{2}|[0-7]{1,3})', String.Escape)
|
| 612 |
+
],
|
| 613 |
+
'strings-single': innerstring_rules(String.Single),
|
| 614 |
+
'strings-double': innerstring_rules(String.Double),
|
| 615 |
+
'dqs': [
|
| 616 |
+
(r'"', String.Double, '#pop'),
|
| 617 |
+
(r'\\\\|\\"|\\\n', String.Escape), # included here for raw strings
|
| 618 |
+
include('strings-double')
|
| 619 |
+
],
|
| 620 |
+
'sqs': [
|
| 621 |
+
(r"'", String.Single, '#pop'),
|
| 622 |
+
(r"\\\\|\\'|\\\n", String.Escape), # included here for raw strings
|
| 623 |
+
include('strings-single')
|
| 624 |
+
],
|
| 625 |
+
'tdqs': [
|
| 626 |
+
(r'"""', String.Double, '#pop'),
|
| 627 |
+
include('strings-double'),
|
| 628 |
+
(r'\n', String.Double)
|
| 629 |
+
],
|
| 630 |
+
'tsqs': [
|
| 631 |
+
(r"'''", String.Single, '#pop'),
|
| 632 |
+
include('strings-single'),
|
| 633 |
+
(r'\n', String.Single)
|
| 634 |
+
],
|
| 635 |
+
}
|
| 636 |
+
|
| 637 |
+
def analyse_text(text):
|
| 638 |
+
return shebang_matches(text, r'pythonw?2(\.\d)?')
|
| 639 |
+
|
| 640 |
+
|
| 641 |
+
class _PythonConsoleLexerBase(RegexLexer):
|
| 642 |
+
name = 'Python console session'
|
| 643 |
+
aliases = ['pycon', 'python-console']
|
| 644 |
+
mimetypes = ['text/x-python-doctest']
|
| 645 |
+
|
| 646 |
+
"""Auxiliary lexer for `PythonConsoleLexer`.
|
| 647 |
+
|
| 648 |
+
Code tokens are output as ``Token.Other.Code``, traceback tokens as
|
| 649 |
+
``Token.Other.Traceback``.
|
| 650 |
+
"""
|
| 651 |
+
tokens = {
|
| 652 |
+
'root': [
|
| 653 |
+
(r'(>>> )(.*\n)', bygroups(Generic.Prompt, Other.Code), 'continuations'),
|
| 654 |
+
# This happens, e.g., when tracebacks are embedded in documentation;
|
| 655 |
+
# trailing whitespaces are often stripped in such contexts.
|
| 656 |
+
(r'(>>>)(\n)', bygroups(Generic.Prompt, Whitespace)),
|
| 657 |
+
(r'(\^C)?Traceback \(most recent call last\):\n', Other.Traceback, 'traceback'),
|
| 658 |
+
# SyntaxError starts with this
|
| 659 |
+
(r' File "[^"]+", line \d+', Other.Traceback, 'traceback'),
|
| 660 |
+
(r'.*\n', Generic.Output),
|
| 661 |
+
],
|
| 662 |
+
'continuations': [
|
| 663 |
+
(r'(\.\.\. )(.*\n)', bygroups(Generic.Prompt, Other.Code)),
|
| 664 |
+
# See above.
|
| 665 |
+
(r'(\.\.\.)(\n)', bygroups(Generic.Prompt, Whitespace)),
|
| 666 |
+
default('#pop'),
|
| 667 |
+
],
|
| 668 |
+
'traceback': [
|
| 669 |
+
# As soon as we see a traceback, consume everything until the next
|
| 670 |
+
# >>> prompt.
|
| 671 |
+
(r'(?=>>>( |$))', Text, '#pop'),
|
| 672 |
+
(r'(KeyboardInterrupt)(\n)', bygroups(Name.Class, Whitespace)),
|
| 673 |
+
(r'.*\n', Other.Traceback),
|
| 674 |
+
],
|
| 675 |
+
}
|
| 676 |
+
|
| 677 |
+
|
| 678 |
+
class PythonConsoleLexer(DelegatingLexer):
|
| 679 |
+
"""
|
| 680 |
+
For Python console output or doctests, such as:
|
| 681 |
+
|
| 682 |
+
.. sourcecode:: pycon
|
| 683 |
+
|
| 684 |
+
>>> a = 'foo'
|
| 685 |
+
>>> print(a)
|
| 686 |
+
foo
|
| 687 |
+
>>> 1 / 0
|
| 688 |
+
Traceback (most recent call last):
|
| 689 |
+
File "<stdin>", line 1, in <module>
|
| 690 |
+
ZeroDivisionError: integer division or modulo by zero
|
| 691 |
+
|
| 692 |
+
Additional options:
|
| 693 |
+
|
| 694 |
+
`python3`
|
| 695 |
+
Use Python 3 lexer for code. Default is ``True``.
|
| 696 |
+
|
| 697 |
+
.. versionadded:: 1.0
|
| 698 |
+
.. versionchanged:: 2.5
|
| 699 |
+
Now defaults to ``True``.
|
| 700 |
+
"""
|
| 701 |
+
|
| 702 |
+
name = 'Python console session'
|
| 703 |
+
aliases = ['pycon', 'python-console']
|
| 704 |
+
mimetypes = ['text/x-python-doctest']
|
| 705 |
+
url = 'https://python.org'
|
| 706 |
+
version_added = ''
|
| 707 |
+
|
| 708 |
+
def __init__(self, **options):
|
| 709 |
+
python3 = get_bool_opt(options, 'python3', True)
|
| 710 |
+
if python3:
|
| 711 |
+
pylexer = PythonLexer
|
| 712 |
+
tblexer = PythonTracebackLexer
|
| 713 |
+
else:
|
| 714 |
+
pylexer = Python2Lexer
|
| 715 |
+
tblexer = Python2TracebackLexer
|
| 716 |
+
# We have two auxiliary lexers. Use DelegatingLexer twice with
|
| 717 |
+
# different tokens. TODO: DelegatingLexer should support this
|
| 718 |
+
# directly, by accepting a tuplet of auxiliary lexers and a tuple of
|
| 719 |
+
# distinguishing tokens. Then we wouldn't need this intermediary
|
| 720 |
+
# class.
|
| 721 |
+
class _ReplaceInnerCode(DelegatingLexer):
|
| 722 |
+
def __init__(self, **options):
|
| 723 |
+
super().__init__(pylexer, _PythonConsoleLexerBase, Other.Code, **options)
|
| 724 |
+
super().__init__(tblexer, _ReplaceInnerCode, Other.Traceback, **options)
|
| 725 |
+
|
| 726 |
+
|
| 727 |
+
class PythonTracebackLexer(RegexLexer):
|
| 728 |
+
"""
|
| 729 |
+
For Python 3.x tracebacks, with support for chained exceptions.
|
| 730 |
+
|
| 731 |
+
.. versionchanged:: 2.5
|
| 732 |
+
This is now the default ``PythonTracebackLexer``. It is still available
|
| 733 |
+
as the alias ``Python3TracebackLexer``.
|
| 734 |
+
"""
|
| 735 |
+
|
| 736 |
+
name = 'Python Traceback'
|
| 737 |
+
aliases = ['pytb', 'py3tb']
|
| 738 |
+
filenames = ['*.pytb', '*.py3tb']
|
| 739 |
+
mimetypes = ['text/x-python-traceback', 'text/x-python3-traceback']
|
| 740 |
+
url = 'https://python.org'
|
| 741 |
+
version_added = '1.0'
|
| 742 |
+
|
| 743 |
+
tokens = {
|
| 744 |
+
'root': [
|
| 745 |
+
(r'\n', Whitespace),
|
| 746 |
+
(r'^(\^C)?Traceback \(most recent call last\):\n', Generic.Traceback, 'intb'),
|
| 747 |
+
(r'^During handling of the above exception, another '
|
| 748 |
+
r'exception occurred:\n\n', Generic.Traceback),
|
| 749 |
+
(r'^The above exception was the direct cause of the '
|
| 750 |
+
r'following exception:\n\n', Generic.Traceback),
|
| 751 |
+
(r'^(?= File "[^"]+", line \d+)', Generic.Traceback, 'intb'),
|
| 752 |
+
(r'^.*\n', Other),
|
| 753 |
+
],
|
| 754 |
+
'intb': [
|
| 755 |
+
(r'^( File )("[^"]+")(, line )(\d+)(, in )(.+)(\n)',
|
| 756 |
+
bygroups(Text, Name.Builtin, Text, Number, Text, Name, Whitespace)),
|
| 757 |
+
(r'^( File )("[^"]+")(, line )(\d+)(\n)',
|
| 758 |
+
bygroups(Text, Name.Builtin, Text, Number, Whitespace)),
|
| 759 |
+
(r'^( )(.+)(\n)',
|
| 760 |
+
bygroups(Whitespace, using(PythonLexer), Whitespace), 'markers'),
|
| 761 |
+
(r'^([ \t]*)(\.\.\.)(\n)',
|
| 762 |
+
bygroups(Whitespace, Comment, Whitespace)), # for doctests...
|
| 763 |
+
(r'^([^:]+)(: )(.+)(\n)',
|
| 764 |
+
bygroups(Generic.Error, Text, Name, Whitespace), '#pop'),
|
| 765 |
+
(r'^([a-zA-Z_][\w.]*)(:?\n)',
|
| 766 |
+
bygroups(Generic.Error, Whitespace), '#pop'),
|
| 767 |
+
default('#pop'),
|
| 768 |
+
],
|
| 769 |
+
'markers': [
|
| 770 |
+
# Either `PEP 657 <https://www.python.org/dev/peps/pep-0657/>`
|
| 771 |
+
# error locations in Python 3.11+, or single-caret markers
|
| 772 |
+
# for syntax errors before that.
|
| 773 |
+
(r'^( {4,})([~^]+)(\n)',
|
| 774 |
+
bygroups(Whitespace, Punctuation.Marker, Whitespace),
|
| 775 |
+
'#pop'),
|
| 776 |
+
default('#pop'),
|
| 777 |
+
],
|
| 778 |
+
}
|
| 779 |
+
|
| 780 |
+
|
| 781 |
+
Python3TracebackLexer = PythonTracebackLexer
|
| 782 |
+
|
| 783 |
+
|
| 784 |
+
class Python2TracebackLexer(RegexLexer):
|
| 785 |
+
"""
|
| 786 |
+
For Python tracebacks.
|
| 787 |
+
|
| 788 |
+
.. versionchanged:: 2.5
|
| 789 |
+
This class has been renamed from ``PythonTracebackLexer``.
|
| 790 |
+
``PythonTracebackLexer`` now refers to the Python 3 variant.
|
| 791 |
+
"""
|
| 792 |
+
|
| 793 |
+
name = 'Python 2.x Traceback'
|
| 794 |
+
aliases = ['py2tb']
|
| 795 |
+
filenames = ['*.py2tb']
|
| 796 |
+
mimetypes = ['text/x-python2-traceback']
|
| 797 |
+
url = 'https://python.org'
|
| 798 |
+
version_added = '0.7'
|
| 799 |
+
|
| 800 |
+
tokens = {
|
| 801 |
+
'root': [
|
| 802 |
+
# Cover both (most recent call last) and (innermost last)
|
| 803 |
+
# The optional ^C allows us to catch keyboard interrupt signals.
|
| 804 |
+
(r'^(\^C)?(Traceback.*\n)',
|
| 805 |
+
bygroups(Text, Generic.Traceback), 'intb'),
|
| 806 |
+
# SyntaxError starts with this.
|
| 807 |
+
(r'^(?= File "[^"]+", line \d+)', Generic.Traceback, 'intb'),
|
| 808 |
+
(r'^.*\n', Other),
|
| 809 |
+
],
|
| 810 |
+
'intb': [
|
| 811 |
+
(r'^( File )("[^"]+")(, line )(\d+)(, in )(.+)(\n)',
|
| 812 |
+
bygroups(Text, Name.Builtin, Text, Number, Text, Name, Whitespace)),
|
| 813 |
+
(r'^( File )("[^"]+")(, line )(\d+)(\n)',
|
| 814 |
+
bygroups(Text, Name.Builtin, Text, Number, Whitespace)),
|
| 815 |
+
(r'^( )(.+)(\n)',
|
| 816 |
+
bygroups(Text, using(Python2Lexer), Whitespace), 'marker'),
|
| 817 |
+
(r'^([ \t]*)(\.\.\.)(\n)',
|
| 818 |
+
bygroups(Text, Comment, Whitespace)), # for doctests...
|
| 819 |
+
(r'^([^:]+)(: )(.+)(\n)',
|
| 820 |
+
bygroups(Generic.Error, Text, Name, Whitespace), '#pop'),
|
| 821 |
+
(r'^([a-zA-Z_]\w*)(:?\n)',
|
| 822 |
+
bygroups(Generic.Error, Whitespace), '#pop')
|
| 823 |
+
],
|
| 824 |
+
'marker': [
|
| 825 |
+
# For syntax errors.
|
| 826 |
+
(r'( {4,})(\^)', bygroups(Text, Punctuation.Marker), '#pop'),
|
| 827 |
+
default('#pop'),
|
| 828 |
+
],
|
| 829 |
+
}
|
| 830 |
+
|
| 831 |
+
|
| 832 |
+
class CythonLexer(RegexLexer):
|
| 833 |
+
"""
|
| 834 |
+
For Pyrex and Cython source code.
|
| 835 |
+
"""
|
| 836 |
+
|
| 837 |
+
name = 'Cython'
|
| 838 |
+
url = 'https://cython.org'
|
| 839 |
+
aliases = ['cython', 'pyx', 'pyrex']
|
| 840 |
+
filenames = ['*.pyx', '*.pxd', '*.pxi']
|
| 841 |
+
mimetypes = ['text/x-cython', 'application/x-cython']
|
| 842 |
+
version_added = '1.1'
|
| 843 |
+
|
| 844 |
+
tokens = {
|
| 845 |
+
'root': [
|
| 846 |
+
(r'\n', Whitespace),
|
| 847 |
+
(r'^(\s*)("""(?:.|\n)*?""")', bygroups(Whitespace, String.Doc)),
|
| 848 |
+
(r"^(\s*)('''(?:.|\n)*?''')", bygroups(Whitespace, String.Doc)),
|
| 849 |
+
(r'[^\S\n]+', Text),
|
| 850 |
+
(r'#.*$', Comment),
|
| 851 |
+
(r'[]{}:(),;[]', Punctuation),
|
| 852 |
+
(r'\\\n', Whitespace),
|
| 853 |
+
(r'\\', Text),
|
| 854 |
+
(r'(in|is|and|or|not)\b', Operator.Word),
|
| 855 |
+
(r'(<)([a-zA-Z0-9.?]+)(>)',
|
| 856 |
+
bygroups(Punctuation, Keyword.Type, Punctuation)),
|
| 857 |
+
(r'!=|==|<<|>>|[-~+/*%=<>&^|.?]', Operator),
|
| 858 |
+
(r'(from)(\d+)(<=)(\s+)(<)(\d+)(:)',
|
| 859 |
+
bygroups(Keyword, Number.Integer, Operator, Whitespace, Operator,
|
| 860 |
+
Name, Punctuation)),
|
| 861 |
+
include('keywords'),
|
| 862 |
+
(r'(def|property)(\s+)', bygroups(Keyword, Whitespace), 'funcname'),
|
| 863 |
+
(r'(cp?def)(\s+)', bygroups(Keyword, Whitespace), 'cdef'),
|
| 864 |
+
# (should actually start a block with only cdefs)
|
| 865 |
+
(r'(cdef)(:)', bygroups(Keyword, Punctuation)),
|
| 866 |
+
(r'(class|cppclass|struct)(\s+)', bygroups(Keyword, Whitespace), 'classname'),
|
| 867 |
+
(r'(from)(\s+)', bygroups(Keyword, Whitespace), 'fromimport'),
|
| 868 |
+
(r'(c?import)(\s+)', bygroups(Keyword, Whitespace), 'import'),
|
| 869 |
+
include('builtins'),
|
| 870 |
+
include('backtick'),
|
| 871 |
+
('(?:[rR]|[uU][rR]|[rR][uU])"""', String, 'tdqs'),
|
| 872 |
+
("(?:[rR]|[uU][rR]|[rR][uU])'''", String, 'tsqs'),
|
| 873 |
+
('(?:[rR]|[uU][rR]|[rR][uU])"', String, 'dqs'),
|
| 874 |
+
("(?:[rR]|[uU][rR]|[rR][uU])'", String, 'sqs'),
|
| 875 |
+
('[uU]?"""', String, combined('stringescape', 'tdqs')),
|
| 876 |
+
("[uU]?'''", String, combined('stringescape', 'tsqs')),
|
| 877 |
+
('[uU]?"', String, combined('stringescape', 'dqs')),
|
| 878 |
+
("[uU]?'", String, combined('stringescape', 'sqs')),
|
| 879 |
+
include('name'),
|
| 880 |
+
include('numbers'),
|
| 881 |
+
],
|
| 882 |
+
'keywords': [
|
| 883 |
+
(words((
|
| 884 |
+
'assert', 'async', 'await', 'break', 'by', 'continue', 'ctypedef', 'del',
|
| 885 |
+
'elif', 'else', 'except', 'except?', 'exec', 'finally', 'for', 'fused', 'gil',
|
| 886 |
+
'global', 'if', 'include', 'lambda', 'namespace', 'new', 'noexcept','nogil',
|
| 887 |
+
'pass', 'print', 'raise', 'return', 'try', 'while', 'yield', 'as', 'with'),
|
| 888 |
+
suffix=r'\b'),
|
| 889 |
+
Keyword),
|
| 890 |
+
(words(('True', 'False', 'None', 'NULL'), suffix=r'\b'), Keyword.Constant),
|
| 891 |
+
(r'(DEF|IF|ELIF|ELSE)\b', Comment.Preproc),
|
| 892 |
+
],
|
| 893 |
+
'builtins': [
|
| 894 |
+
(words((
|
| 895 |
+
'__import__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bint',
|
| 896 |
+
'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'char', 'chr',
|
| 897 |
+
'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'delattr',
|
| 898 |
+
'dict', 'dir', 'divmod', 'double', 'enumerate', 'eval', 'execfile', 'exit',
|
| 899 |
+
'file', 'filter', 'float', 'frozenset', 'getattr', 'globals',
|
| 900 |
+
'hasattr', 'hash', 'hex', 'id', 'input', 'int', 'intern', 'isinstance',
|
| 901 |
+
'issubclass', 'iter', 'len', 'list', 'locals', 'long', 'map', 'max',
|
| 902 |
+
'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'property',
|
| 903 |
+
'Py_ssize_t', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed',
|
| 904 |
+
'round', 'set', 'setattr', 'size_t', 'slice', 'sorted', 'staticmethod',
|
| 905 |
+
'ssize_t', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode',
|
| 906 |
+
'unsigned', 'vars', 'xrange', 'zip'), prefix=r'(?<!\.)', suffix=r'\b'),
|
| 907 |
+
Name.Builtin),
|
| 908 |
+
(r'(?<!\.)(self|cls|Ellipsis|NotImplemented)\b', Name.Builtin.Pseudo),
|
| 909 |
+
(words((
|
| 910 |
+
'ArithmeticError', 'AssertionError', 'AttributeError',
|
| 911 |
+
'BaseException', 'DeprecationWarning', 'EOFError', 'EnvironmentError',
|
| 912 |
+
'Exception', 'FloatingPointError', 'FutureWarning', 'GeneratorExit',
|
| 913 |
+
'IOError', 'ImportError', 'ImportWarning', 'IndentationError',
|
| 914 |
+
'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError',
|
| 915 |
+
'MemoryError', 'NameError', 'NotImplementedError',
|
| 916 |
+
'OSError', 'OverflowError', 'OverflowWarning',
|
| 917 |
+
'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError',
|
| 918 |
+
'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError',
|
| 919 |
+
'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError',
|
| 920 |
+
'TypeError', 'UnboundLocalError', 'UnicodeDecodeError',
|
| 921 |
+
'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError',
|
| 922 |
+
'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning',
|
| 923 |
+
'ZeroDivisionError'), prefix=r'(?<!\.)', suffix=r'\b'),
|
| 924 |
+
Name.Exception),
|
| 925 |
+
],
|
| 926 |
+
'numbers': [
|
| 927 |
+
(r'(\d+\.?\d*|\d*\.\d+)([eE][+-]?[0-9]+)?', Number.Float),
|
| 928 |
+
(r'0\d+', Number.Oct),
|
| 929 |
+
(r'0[xX][a-fA-F0-9]+', Number.Hex),
|
| 930 |
+
(r'\d+L', Number.Integer.Long),
|
| 931 |
+
(r'\d+', Number.Integer)
|
| 932 |
+
],
|
| 933 |
+
'backtick': [
|
| 934 |
+
('`.*?`', String.Backtick),
|
| 935 |
+
],
|
| 936 |
+
'name': [
|
| 937 |
+
(r'@\w+', Name.Decorator),
|
| 938 |
+
(r'[a-zA-Z_]\w*', Name),
|
| 939 |
+
],
|
| 940 |
+
'funcname': [
|
| 941 |
+
(r'[a-zA-Z_]\w*', Name.Function, '#pop')
|
| 942 |
+
],
|
| 943 |
+
'cdef': [
|
| 944 |
+
(r"(public|readonly|extern|api|inline|packed)\b", Keyword.Reserved),
|
| 945 |
+
(r"(struct|enum|union|class|cppclass)\b(\s+)([a-zA-Z_]\w*)",
|
| 946 |
+
bygroups(Keyword, Whitespace, Name.Class), "#pop",),
|
| 947 |
+
(r"([a-zA-Z_]\w*)(\s*)(?=\()", bygroups(Name.Function, Whitespace), "#pop"),
|
| 948 |
+
(r"([a-zA-Z_]\w*)(\s*)(?=[:,=#\n]|$)", bygroups(Name.Variable, Whitespace), "#pop"),
|
| 949 |
+
(r"([a-zA-Z_]\w*)(\s*)(,)", bygroups(Name.Variable, Whitespace, Punctuation)),
|
| 950 |
+
(r'from\b', Keyword, '#pop'),
|
| 951 |
+
(r'as\b', Keyword),
|
| 952 |
+
(r':', Punctuation, '#pop'),
|
| 953 |
+
(r'(?=["\'])', Text, '#pop'),
|
| 954 |
+
(r'[a-zA-Z_]\w*', Keyword.Type),
|
| 955 |
+
(r'.', Text),
|
| 956 |
+
],
|
| 957 |
+
'classname': [
|
| 958 |
+
(r'[a-zA-Z_]\w*', Name.Class, '#pop')
|
| 959 |
+
],
|
| 960 |
+
'import': [
|
| 961 |
+
(r'(\s+)(as)(\s+)', bygroups(Whitespace, Keyword, Whitespace)),
|
| 962 |
+
(r'[a-zA-Z_][\w.]*', Name.Namespace),
|
| 963 |
+
(r'(\s*)(,)(\s*)', bygroups(Whitespace, Operator, Whitespace)),
|
| 964 |
+
default('#pop') # all else: go back
|
| 965 |
+
],
|
| 966 |
+
'fromimport': [
|
| 967 |
+
(r'(\s+)(c?import)\b', bygroups(Whitespace, Keyword), '#pop'),
|
| 968 |
+
(r'[a-zA-Z_.][\w.]*', Name.Namespace),
|
| 969 |
+
# ``cdef foo from "header"``, or ``for foo from 0 < i < 10``
|
| 970 |
+
default('#pop'),
|
| 971 |
+
],
|
| 972 |
+
'stringescape': [
|
| 973 |
+
(r'\\([\\abfnrtv"\']|\n|N\{.*?\}|u[a-fA-F0-9]{4}|'
|
| 974 |
+
r'U[a-fA-F0-9]{8}|x[a-fA-F0-9]{2}|[0-7]{1,3})', String.Escape)
|
| 975 |
+
],
|
| 976 |
+
'strings': [
|
| 977 |
+
(r'%(\([a-zA-Z0-9]+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?'
|
| 978 |
+
'[hlL]?[E-GXc-giorsux%]', String.Interpol),
|
| 979 |
+
(r'[^\\\'"%\n]+', String),
|
| 980 |
+
# quotes, percents and backslashes must be parsed one at a time
|
| 981 |
+
(r'[\'"\\]', String),
|
| 982 |
+
# unhandled string formatting sign
|
| 983 |
+
(r'%', String)
|
| 984 |
+
# newlines are an error (use "nl" state)
|
| 985 |
+
],
|
| 986 |
+
'nl': [
|
| 987 |
+
(r'\n', String)
|
| 988 |
+
],
|
| 989 |
+
'dqs': [
|
| 990 |
+
(r'"', String, '#pop'),
|
| 991 |
+
(r'\\\\|\\"|\\\n', String.Escape), # included here again for raw strings
|
| 992 |
+
include('strings')
|
| 993 |
+
],
|
| 994 |
+
'sqs': [
|
| 995 |
+
(r"'", String, '#pop'),
|
| 996 |
+
(r"\\\\|\\'|\\\n", String.Escape), # included here again for raw strings
|
| 997 |
+
include('strings')
|
| 998 |
+
],
|
| 999 |
+
'tdqs': [
|
| 1000 |
+
(r'"""', String, '#pop'),
|
| 1001 |
+
include('strings'),
|
| 1002 |
+
include('nl')
|
| 1003 |
+
],
|
| 1004 |
+
'tsqs': [
|
| 1005 |
+
(r"'''", String, '#pop'),
|
| 1006 |
+
include('strings'),
|
| 1007 |
+
include('nl')
|
| 1008 |
+
],
|
| 1009 |
+
}
|
| 1010 |
+
|
| 1011 |
+
|
| 1012 |
+
class DgLexer(RegexLexer):
|
| 1013 |
+
"""
|
| 1014 |
+
Lexer for dg,
|
| 1015 |
+
a functional and object-oriented programming language
|
| 1016 |
+
running on the CPython 3 VM.
|
| 1017 |
+
"""
|
| 1018 |
+
name = 'dg'
|
| 1019 |
+
aliases = ['dg']
|
| 1020 |
+
filenames = ['*.dg']
|
| 1021 |
+
mimetypes = ['text/x-dg']
|
| 1022 |
+
url = 'http://pyos.github.io/dg'
|
| 1023 |
+
version_added = '1.6'
|
| 1024 |
+
|
| 1025 |
+
tokens = {
|
| 1026 |
+
'root': [
|
| 1027 |
+
(r'\s+', Text),
|
| 1028 |
+
(r'#.*?$', Comment.Single),
|
| 1029 |
+
|
| 1030 |
+
(r'(?i)0b[01]+', Number.Bin),
|
| 1031 |
+
(r'(?i)0o[0-7]+', Number.Oct),
|
| 1032 |
+
(r'(?i)0x[0-9a-f]+', Number.Hex),
|
| 1033 |
+
(r'(?i)[+-]?[0-9]+\.[0-9]+(e[+-]?[0-9]+)?j?', Number.Float),
|
| 1034 |
+
(r'(?i)[+-]?[0-9]+e[+-]?\d+j?', Number.Float),
|
| 1035 |
+
(r'(?i)[+-]?[0-9]+j?', Number.Integer),
|
| 1036 |
+
|
| 1037 |
+
(r"(?i)(br|r?b?)'''", String, combined('stringescape', 'tsqs', 'string')),
|
| 1038 |
+
(r'(?i)(br|r?b?)"""', String, combined('stringescape', 'tdqs', 'string')),
|
| 1039 |
+
(r"(?i)(br|r?b?)'", String, combined('stringescape', 'sqs', 'string')),
|
| 1040 |
+
(r'(?i)(br|r?b?)"', String, combined('stringescape', 'dqs', 'string')),
|
| 1041 |
+
|
| 1042 |
+
(r"`\w+'*`", Operator),
|
| 1043 |
+
(r'\b(and|in|is|or|where)\b', Operator.Word),
|
| 1044 |
+
(r'[!$%&*+\-./:<-@\\^|~;,]+', Operator),
|
| 1045 |
+
|
| 1046 |
+
(words((
|
| 1047 |
+
'bool', 'bytearray', 'bytes', 'classmethod', 'complex', 'dict', 'dict\'',
|
| 1048 |
+
'float', 'frozenset', 'int', 'list', 'list\'', 'memoryview', 'object',
|
| 1049 |
+
'property', 'range', 'set', 'set\'', 'slice', 'staticmethod', 'str',
|
| 1050 |
+
'super', 'tuple', 'tuple\'', 'type'),
|
| 1051 |
+
prefix=r'(?<!\.)', suffix=r'(?![\'\w])'),
|
| 1052 |
+
Name.Builtin),
|
| 1053 |
+
(words((
|
| 1054 |
+
'__import__', 'abs', 'all', 'any', 'bin', 'bind', 'chr', 'cmp', 'compile',
|
| 1055 |
+
'complex', 'delattr', 'dir', 'divmod', 'drop', 'dropwhile', 'enumerate',
|
| 1056 |
+
'eval', 'exhaust', 'filter', 'flip', 'foldl1?', 'format', 'fst',
|
| 1057 |
+
'getattr', 'globals', 'hasattr', 'hash', 'head', 'hex', 'id', 'init',
|
| 1058 |
+
'input', 'isinstance', 'issubclass', 'iter', 'iterate', 'last', 'len',
|
| 1059 |
+
'locals', 'map', 'max', 'min', 'next', 'oct', 'open', 'ord', 'pow',
|
| 1060 |
+
'print', 'repr', 'reversed', 'round', 'setattr', 'scanl1?', 'snd',
|
| 1061 |
+
'sorted', 'sum', 'tail', 'take', 'takewhile', 'vars', 'zip'),
|
| 1062 |
+
prefix=r'(?<!\.)', suffix=r'(?![\'\w])'),
|
| 1063 |
+
Name.Builtin),
|
| 1064 |
+
(r"(?<!\.)(self|Ellipsis|NotImplemented|None|True|False)(?!['\w])",
|
| 1065 |
+
Name.Builtin.Pseudo),
|
| 1066 |
+
|
| 1067 |
+
(r"(?<!\.)[A-Z]\w*(Error|Exception|Warning)'*(?!['\w])",
|
| 1068 |
+
Name.Exception),
|
| 1069 |
+
(r"(?<!\.)(Exception|GeneratorExit|KeyboardInterrupt|StopIteration|"
|
| 1070 |
+
r"SystemExit)(?!['\w])", Name.Exception),
|
| 1071 |
+
|
| 1072 |
+
(r"(?<![\w.])(except|finally|for|if|import|not|otherwise|raise|"
|
| 1073 |
+
r"subclass|while|with|yield)(?!['\w])", Keyword.Reserved),
|
| 1074 |
+
|
| 1075 |
+
(r"[A-Z_]+'*(?!['\w])", Name),
|
| 1076 |
+
(r"[A-Z]\w+'*(?!['\w])", Keyword.Type),
|
| 1077 |
+
(r"\w+'*", Name),
|
| 1078 |
+
|
| 1079 |
+
(r'[()]', Punctuation),
|
| 1080 |
+
(r'.', Error),
|
| 1081 |
+
],
|
| 1082 |
+
'stringescape': [
|
| 1083 |
+
(r'\\([\\abfnrtv"\']|\n|N\{.*?\}|u[a-fA-F0-9]{4}|'
|
| 1084 |
+
r'U[a-fA-F0-9]{8}|x[a-fA-F0-9]{2}|[0-7]{1,3})', String.Escape)
|
| 1085 |
+
],
|
| 1086 |
+
'string': [
|
| 1087 |
+
(r'%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?'
|
| 1088 |
+
'[hlL]?[E-GXc-giorsux%]', String.Interpol),
|
| 1089 |
+
(r'[^\\\'"%\n]+', String),
|
| 1090 |
+
# quotes, percents and backslashes must be parsed one at a time
|
| 1091 |
+
(r'[\'"\\]', String),
|
| 1092 |
+
# unhandled string formatting sign
|
| 1093 |
+
(r'%', String),
|
| 1094 |
+
(r'\n', String)
|
| 1095 |
+
],
|
| 1096 |
+
'dqs': [
|
| 1097 |
+
(r'"', String, '#pop')
|
| 1098 |
+
],
|
| 1099 |
+
'sqs': [
|
| 1100 |
+
(r"'", String, '#pop')
|
| 1101 |
+
],
|
| 1102 |
+
'tdqs': [
|
| 1103 |
+
(r'"""', String, '#pop')
|
| 1104 |
+
],
|
| 1105 |
+
'tsqs': [
|
| 1106 |
+
(r"'''", String, '#pop')
|
| 1107 |
+
],
|
| 1108 |
+
}
|
| 1109 |
+
|
| 1110 |
+
|
| 1111 |
+
class NumPyLexer(PythonLexer):
|
| 1112 |
+
"""
|
| 1113 |
+
A Python lexer recognizing Numerical Python builtins.
|
| 1114 |
+
"""
|
| 1115 |
+
|
| 1116 |
+
name = 'NumPy'
|
| 1117 |
+
url = 'https://numpy.org/'
|
| 1118 |
+
aliases = ['numpy']
|
| 1119 |
+
version_added = '0.10'
|
| 1120 |
+
|
| 1121 |
+
# override the mimetypes to not inherit them from python
|
| 1122 |
+
mimetypes = []
|
| 1123 |
+
filenames = []
|
| 1124 |
+
|
| 1125 |
+
EXTRA_KEYWORDS = {
|
| 1126 |
+
'abs', 'absolute', 'accumulate', 'add', 'alen', 'all', 'allclose',
|
| 1127 |
+
'alltrue', 'alterdot', 'amax', 'amin', 'angle', 'any', 'append',
|
| 1128 |
+
'apply_along_axis', 'apply_over_axes', 'arange', 'arccos', 'arccosh',
|
| 1129 |
+
'arcsin', 'arcsinh', 'arctan', 'arctan2', 'arctanh', 'argmax', 'argmin',
|
| 1130 |
+
'argsort', 'argwhere', 'around', 'array', 'array2string', 'array_equal',
|
| 1131 |
+
'array_equiv', 'array_repr', 'array_split', 'array_str', 'arrayrange',
|
| 1132 |
+
'asanyarray', 'asarray', 'asarray_chkfinite', 'ascontiguousarray',
|
| 1133 |
+
'asfarray', 'asfortranarray', 'asmatrix', 'asscalar', 'astype',
|
| 1134 |
+
'atleast_1d', 'atleast_2d', 'atleast_3d', 'average', 'bartlett',
|
| 1135 |
+
'base_repr', 'beta', 'binary_repr', 'bincount', 'binomial',
|
| 1136 |
+
'bitwise_and', 'bitwise_not', 'bitwise_or', 'bitwise_xor', 'blackman',
|
| 1137 |
+
'bmat', 'broadcast', 'byte_bounds', 'bytes', 'byteswap', 'c_',
|
| 1138 |
+
'can_cast', 'ceil', 'choose', 'clip', 'column_stack', 'common_type',
|
| 1139 |
+
'compare_chararrays', 'compress', 'concatenate', 'conj', 'conjugate',
|
| 1140 |
+
'convolve', 'copy', 'corrcoef', 'correlate', 'cos', 'cosh', 'cov',
|
| 1141 |
+
'cross', 'cumprod', 'cumproduct', 'cumsum', 'delete', 'deprecate',
|
| 1142 |
+
'diag', 'diagflat', 'diagonal', 'diff', 'digitize', 'disp', 'divide',
|
| 1143 |
+
'dot', 'dsplit', 'dstack', 'dtype', 'dump', 'dumps', 'ediff1d', 'empty',
|
| 1144 |
+
'empty_like', 'equal', 'exp', 'expand_dims', 'expm1', 'extract', 'eye',
|
| 1145 |
+
'fabs', 'fastCopyAndTranspose', 'fft', 'fftfreq', 'fftshift', 'fill',
|
| 1146 |
+
'finfo', 'fix', 'flat', 'flatnonzero', 'flatten', 'fliplr', 'flipud',
|
| 1147 |
+
'floor', 'floor_divide', 'fmod', 'frexp', 'fromarrays', 'frombuffer',
|
| 1148 |
+
'fromfile', 'fromfunction', 'fromiter', 'frompyfunc', 'fromstring',
|
| 1149 |
+
'generic', 'get_array_wrap', 'get_include', 'get_numarray_include',
|
| 1150 |
+
'get_numpy_include', 'get_printoptions', 'getbuffer', 'getbufsize',
|
| 1151 |
+
'geterr', 'geterrcall', 'geterrobj', 'getfield', 'gradient', 'greater',
|
| 1152 |
+
'greater_equal', 'gumbel', 'hamming', 'hanning', 'histogram',
|
| 1153 |
+
'histogram2d', 'histogramdd', 'hsplit', 'hstack', 'hypot', 'i0',
|
| 1154 |
+
'identity', 'ifft', 'imag', 'index_exp', 'indices', 'inf', 'info',
|
| 1155 |
+
'inner', 'insert', 'int_asbuffer', 'interp', 'intersect1d',
|
| 1156 |
+
'intersect1d_nu', 'inv', 'invert', 'iscomplex', 'iscomplexobj',
|
| 1157 |
+
'isfinite', 'isfortran', 'isinf', 'isnan', 'isneginf', 'isposinf',
|
| 1158 |
+
'isreal', 'isrealobj', 'isscalar', 'issctype', 'issubclass_',
|
| 1159 |
+
'issubdtype', 'issubsctype', 'item', 'itemset', 'iterable', 'ix_',
|
| 1160 |
+
'kaiser', 'kron', 'ldexp', 'left_shift', 'less', 'less_equal', 'lexsort',
|
| 1161 |
+
'linspace', 'load', 'loads', 'loadtxt', 'log', 'log10', 'log1p', 'log2',
|
| 1162 |
+
'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'logspace',
|
| 1163 |
+
'lstsq', 'mat', 'matrix', 'max', 'maximum', 'maximum_sctype',
|
| 1164 |
+
'may_share_memory', 'mean', 'median', 'meshgrid', 'mgrid', 'min',
|
| 1165 |
+
'minimum', 'mintypecode', 'mod', 'modf', 'msort', 'multiply', 'nan',
|
| 1166 |
+
'nan_to_num', 'nanargmax', 'nanargmin', 'nanmax', 'nanmin', 'nansum',
|
| 1167 |
+
'ndenumerate', 'ndim', 'ndindex', 'negative', 'newaxis', 'newbuffer',
|
| 1168 |
+
'newbyteorder', 'nonzero', 'not_equal', 'obj2sctype', 'ogrid', 'ones',
|
| 1169 |
+
'ones_like', 'outer', 'permutation', 'piecewise', 'pinv', 'pkgload',
|
| 1170 |
+
'place', 'poisson', 'poly', 'poly1d', 'polyadd', 'polyder', 'polydiv',
|
| 1171 |
+
'polyfit', 'polyint', 'polymul', 'polysub', 'polyval', 'power', 'prod',
|
| 1172 |
+
'product', 'ptp', 'put', 'putmask', 'r_', 'randint', 'random_integers',
|
| 1173 |
+
'random_sample', 'ranf', 'rank', 'ravel', 'real', 'real_if_close',
|
| 1174 |
+
'recarray', 'reciprocal', 'reduce', 'remainder', 'repeat', 'require',
|
| 1175 |
+
'reshape', 'resize', 'restoredot', 'right_shift', 'rint', 'roll',
|
| 1176 |
+
'rollaxis', 'roots', 'rot90', 'round', 'round_', 'row_stack', 's_',
|
| 1177 |
+
'sample', 'savetxt', 'sctype2char', 'searchsorted', 'seed', 'select',
|
| 1178 |
+
'set_numeric_ops', 'set_printoptions', 'set_string_function',
|
| 1179 |
+
'setbufsize', 'setdiff1d', 'seterr', 'seterrcall', 'seterrobj',
|
| 1180 |
+
'setfield', 'setflags', 'setmember1d', 'setxor1d', 'shape',
|
| 1181 |
+
'show_config', 'shuffle', 'sign', 'signbit', 'sin', 'sinc', 'sinh',
|
| 1182 |
+
'size', 'slice', 'solve', 'sometrue', 'sort', 'sort_complex', 'source',
|
| 1183 |
+
'split', 'sqrt', 'square', 'squeeze', 'standard_normal', 'std',
|
| 1184 |
+
'subtract', 'sum', 'svd', 'swapaxes', 'take', 'tan', 'tanh', 'tensordot',
|
| 1185 |
+
'test', 'tile', 'tofile', 'tolist', 'tostring', 'trace', 'transpose',
|
| 1186 |
+
'trapz', 'tri', 'tril', 'trim_zeros', 'triu', 'true_divide', 'typeDict',
|
| 1187 |
+
'typename', 'uniform', 'union1d', 'unique', 'unique1d', 'unravel_index',
|
| 1188 |
+
'unwrap', 'vander', 'var', 'vdot', 'vectorize', 'view', 'vonmises',
|
| 1189 |
+
'vsplit', 'vstack', 'weibull', 'where', 'who', 'zeros', 'zeros_like'
|
| 1190 |
+
}
|
| 1191 |
+
|
| 1192 |
+
def get_tokens_unprocessed(self, text):
|
| 1193 |
+
for index, token, value in \
|
| 1194 |
+
PythonLexer.get_tokens_unprocessed(self, text):
|
| 1195 |
+
if token is Name and value in self.EXTRA_KEYWORDS:
|
| 1196 |
+
yield index, Keyword.Pseudo, value
|
| 1197 |
+
else:
|
| 1198 |
+
yield index, token, value
|
| 1199 |
+
|
| 1200 |
+
def analyse_text(text):
|
| 1201 |
+
ltext = text[:1000]
|
| 1202 |
+
return (shebang_matches(text, r'pythonw?(3(\.\d)?)?') or
|
| 1203 |
+
'import ' in ltext) \
|
| 1204 |
+
and ('import numpy' in ltext or 'from numpy import' in ltext)
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/modeline.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.modeline
|
| 3 |
+
~~~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
A simple modeline parser (based on pymodeline).
|
| 6 |
+
|
| 7 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 8 |
+
:license: BSD, see LICENSE for details.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import re
|
| 12 |
+
|
| 13 |
+
__all__ = ['get_filetype_from_buffer']
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
modeline_re = re.compile(r'''
|
| 17 |
+
(?: vi | vim | ex ) (?: [<=>]? \d* )? :
|
| 18 |
+
.* (?: ft | filetype | syn | syntax ) = ( [^:\s]+ )
|
| 19 |
+
''', re.VERBOSE)
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def get_filetype_from_line(l): # noqa: E741
|
| 23 |
+
m = modeline_re.search(l)
|
| 24 |
+
if m:
|
| 25 |
+
return m.group(1)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def get_filetype_from_buffer(buf, max_lines=5):
|
| 29 |
+
"""
|
| 30 |
+
Scan the buffer for modelines and return filetype if one is found.
|
| 31 |
+
"""
|
| 32 |
+
lines = buf.splitlines()
|
| 33 |
+
for line in lines[-1:-max_lines-1:-1]:
|
| 34 |
+
ret = get_filetype_from_line(line)
|
| 35 |
+
if ret:
|
| 36 |
+
return ret
|
| 37 |
+
for i in range(max_lines, -1, -1):
|
| 38 |
+
if i < len(lines):
|
| 39 |
+
ret = get_filetype_from_line(lines[i])
|
| 40 |
+
if ret:
|
| 41 |
+
return ret
|
| 42 |
+
|
| 43 |
+
return None
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/plugin.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.plugin
|
| 3 |
+
~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Pygments plugin interface.
|
| 6 |
+
|
| 7 |
+
lexer plugins::
|
| 8 |
+
|
| 9 |
+
[pygments.lexers]
|
| 10 |
+
yourlexer = yourmodule:YourLexer
|
| 11 |
+
|
| 12 |
+
formatter plugins::
|
| 13 |
+
|
| 14 |
+
[pygments.formatters]
|
| 15 |
+
yourformatter = yourformatter:YourFormatter
|
| 16 |
+
/.ext = yourformatter:YourFormatter
|
| 17 |
+
|
| 18 |
+
As you can see, you can define extensions for the formatter
|
| 19 |
+
with a leading slash.
|
| 20 |
+
|
| 21 |
+
syntax plugins::
|
| 22 |
+
|
| 23 |
+
[pygments.styles]
|
| 24 |
+
yourstyle = yourstyle:YourStyle
|
| 25 |
+
|
| 26 |
+
filter plugin::
|
| 27 |
+
|
| 28 |
+
[pygments.filter]
|
| 29 |
+
yourfilter = yourfilter:YourFilter
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 33 |
+
:license: BSD, see LICENSE for details.
|
| 34 |
+
"""
|
| 35 |
+
import functools
|
| 36 |
+
from importlib.metadata import entry_points
|
| 37 |
+
|
| 38 |
+
LEXER_ENTRY_POINT = 'pygments.lexers'
|
| 39 |
+
FORMATTER_ENTRY_POINT = 'pygments.formatters'
|
| 40 |
+
STYLE_ENTRY_POINT = 'pygments.styles'
|
| 41 |
+
FILTER_ENTRY_POINT = 'pygments.filters'
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
@functools.cache
|
| 45 |
+
def iter_entry_points(group_name):
|
| 46 |
+
groups = entry_points()
|
| 47 |
+
if hasattr(groups, 'select'):
|
| 48 |
+
# New interface in Python 3.10 and newer versions of the
|
| 49 |
+
# importlib_metadata backport.
|
| 50 |
+
return groups.select(group=group_name)
|
| 51 |
+
else:
|
| 52 |
+
# Older interface, deprecated in Python 3.10 and recent
|
| 53 |
+
# importlib_metadata, but we need it in Python 3.8 and 3.9.
|
| 54 |
+
return groups.get(group_name, [])
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def find_plugin_lexers():
|
| 58 |
+
for entrypoint in iter_entry_points(LEXER_ENTRY_POINT):
|
| 59 |
+
yield entrypoint.load()
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def find_plugin_formatters():
|
| 63 |
+
for entrypoint in iter_entry_points(FORMATTER_ENTRY_POINT):
|
| 64 |
+
yield entrypoint.name, entrypoint.load()
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def find_plugin_styles():
|
| 68 |
+
for entrypoint in iter_entry_points(STYLE_ENTRY_POINT):
|
| 69 |
+
yield entrypoint.name, entrypoint.load()
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def find_plugin_filters():
|
| 73 |
+
for entrypoint in iter_entry_points(FILTER_ENTRY_POINT):
|
| 74 |
+
yield entrypoint.name, entrypoint.load()
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/regexopt.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.regexopt
|
| 3 |
+
~~~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
An algorithm that generates optimized regexes for matching long lists of
|
| 6 |
+
literal strings.
|
| 7 |
+
|
| 8 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 9 |
+
:license: BSD, see LICENSE for details.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import re
|
| 13 |
+
from re import escape
|
| 14 |
+
from itertools import groupby
|
| 15 |
+
from operator import itemgetter
|
| 16 |
+
|
| 17 |
+
CS_ESCAPE = re.compile(r'[\[\^\\\-\]]')
|
| 18 |
+
FIRST_ELEMENT = itemgetter(0)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def commonprefix(m):
|
| 22 |
+
"""Given an iterable of strings, returns the longest common leading substring"""
|
| 23 |
+
if not m:
|
| 24 |
+
return ""
|
| 25 |
+
s1 = min(m)
|
| 26 |
+
s2 = max(m)
|
| 27 |
+
for i, c in enumerate(s1):
|
| 28 |
+
if c != s2[i]:
|
| 29 |
+
return s1[:i]
|
| 30 |
+
return s1
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def make_charset(letters):
|
| 34 |
+
return '[' + CS_ESCAPE.sub(lambda m: '\\' + m.group(), ''.join(letters)) + ']'
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def regex_opt_inner(strings, open_paren):
|
| 38 |
+
"""Return a regex that matches any string in the sorted list of strings."""
|
| 39 |
+
close_paren = open_paren and ')' or ''
|
| 40 |
+
# print strings, repr(open_paren)
|
| 41 |
+
if not strings:
|
| 42 |
+
# print '-> nothing left'
|
| 43 |
+
return ''
|
| 44 |
+
first = strings[0]
|
| 45 |
+
if len(strings) == 1:
|
| 46 |
+
# print '-> only 1 string'
|
| 47 |
+
return open_paren + escape(first) + close_paren
|
| 48 |
+
if not first:
|
| 49 |
+
# print '-> first string empty'
|
| 50 |
+
return open_paren + regex_opt_inner(strings[1:], '(?:') \
|
| 51 |
+
+ '?' + close_paren
|
| 52 |
+
if len(first) == 1:
|
| 53 |
+
# multiple one-char strings? make a charset
|
| 54 |
+
oneletter = []
|
| 55 |
+
rest = []
|
| 56 |
+
for s in strings:
|
| 57 |
+
if len(s) == 1:
|
| 58 |
+
oneletter.append(s)
|
| 59 |
+
else:
|
| 60 |
+
rest.append(s)
|
| 61 |
+
if len(oneletter) > 1: # do we have more than one oneletter string?
|
| 62 |
+
if rest:
|
| 63 |
+
# print '-> 1-character + rest'
|
| 64 |
+
return open_paren + regex_opt_inner(rest, '') + '|' \
|
| 65 |
+
+ make_charset(oneletter) + close_paren
|
| 66 |
+
# print '-> only 1-character'
|
| 67 |
+
return open_paren + make_charset(oneletter) + close_paren
|
| 68 |
+
prefix = commonprefix(strings)
|
| 69 |
+
if prefix:
|
| 70 |
+
plen = len(prefix)
|
| 71 |
+
# we have a prefix for all strings
|
| 72 |
+
# print '-> prefix:', prefix
|
| 73 |
+
return open_paren + escape(prefix) \
|
| 74 |
+
+ regex_opt_inner([s[plen:] for s in strings], '(?:') \
|
| 75 |
+
+ close_paren
|
| 76 |
+
# is there a suffix?
|
| 77 |
+
strings_rev = [s[::-1] for s in strings]
|
| 78 |
+
suffix = commonprefix(strings_rev)
|
| 79 |
+
if suffix:
|
| 80 |
+
slen = len(suffix)
|
| 81 |
+
# print '-> suffix:', suffix[::-1]
|
| 82 |
+
return open_paren \
|
| 83 |
+
+ regex_opt_inner(sorted(s[:-slen] for s in strings), '(?:') \
|
| 84 |
+
+ escape(suffix[::-1]) + close_paren
|
| 85 |
+
# recurse on common 1-string prefixes
|
| 86 |
+
# print '-> last resort'
|
| 87 |
+
return open_paren + \
|
| 88 |
+
'|'.join(regex_opt_inner(list(group[1]), '')
|
| 89 |
+
for group in groupby(strings, lambda s: s[0] == first[0])) \
|
| 90 |
+
+ close_paren
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def regex_opt(strings, prefix='', suffix=''):
|
| 94 |
+
"""Return a compiled regex that matches any string in the given list.
|
| 95 |
+
|
| 96 |
+
The strings to match must be literal strings, not regexes. They will be
|
| 97 |
+
regex-escaped.
|
| 98 |
+
|
| 99 |
+
*prefix* and *suffix* are pre- and appended to the final regex.
|
| 100 |
+
"""
|
| 101 |
+
strings = sorted(strings)
|
| 102 |
+
return prefix + regex_opt_inner(strings, '(') + suffix
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/scanner.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.scanner
|
| 3 |
+
~~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
This library implements a regex based scanner. Some languages
|
| 6 |
+
like Pascal are easy to parse but have some keywords that
|
| 7 |
+
depend on the context. Because of this it's impossible to lex
|
| 8 |
+
that just by using a regular expression lexer like the
|
| 9 |
+
`RegexLexer`.
|
| 10 |
+
|
| 11 |
+
Have a look at the `DelphiLexer` to get an idea of how to use
|
| 12 |
+
this scanner.
|
| 13 |
+
|
| 14 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 15 |
+
:license: BSD, see LICENSE for details.
|
| 16 |
+
"""
|
| 17 |
+
import re
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class EndOfText(RuntimeError):
|
| 21 |
+
"""
|
| 22 |
+
Raise if end of text is reached and the user
|
| 23 |
+
tried to call a match function.
|
| 24 |
+
"""
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
class Scanner:
|
| 28 |
+
"""
|
| 29 |
+
Simple scanner
|
| 30 |
+
|
| 31 |
+
All method patterns are regular expression strings (not
|
| 32 |
+
compiled expressions!)
|
| 33 |
+
"""
|
| 34 |
+
|
| 35 |
+
def __init__(self, text, flags=0):
|
| 36 |
+
"""
|
| 37 |
+
:param text: The text which should be scanned
|
| 38 |
+
:param flags: default regular expression flags
|
| 39 |
+
"""
|
| 40 |
+
self.data = text
|
| 41 |
+
self.data_length = len(text)
|
| 42 |
+
self.start_pos = 0
|
| 43 |
+
self.pos = 0
|
| 44 |
+
self.flags = flags
|
| 45 |
+
self.last = None
|
| 46 |
+
self.match = None
|
| 47 |
+
self._re_cache = {}
|
| 48 |
+
|
| 49 |
+
def eos(self):
|
| 50 |
+
"""`True` if the scanner reached the end of text."""
|
| 51 |
+
return self.pos >= self.data_length
|
| 52 |
+
eos = property(eos, eos.__doc__)
|
| 53 |
+
|
| 54 |
+
def check(self, pattern):
|
| 55 |
+
"""
|
| 56 |
+
Apply `pattern` on the current position and return
|
| 57 |
+
the match object. (Doesn't touch pos). Use this for
|
| 58 |
+
lookahead.
|
| 59 |
+
"""
|
| 60 |
+
if self.eos:
|
| 61 |
+
raise EndOfText()
|
| 62 |
+
if pattern not in self._re_cache:
|
| 63 |
+
self._re_cache[pattern] = re.compile(pattern, self.flags)
|
| 64 |
+
return self._re_cache[pattern].match(self.data, self.pos)
|
| 65 |
+
|
| 66 |
+
def test(self, pattern):
|
| 67 |
+
"""Apply a pattern on the current position and check
|
| 68 |
+
if it patches. Doesn't touch pos.
|
| 69 |
+
"""
|
| 70 |
+
return self.check(pattern) is not None
|
| 71 |
+
|
| 72 |
+
def scan(self, pattern):
|
| 73 |
+
"""
|
| 74 |
+
Scan the text for the given pattern and update pos/match
|
| 75 |
+
and related fields. The return value is a boolean that
|
| 76 |
+
indicates if the pattern matched. The matched value is
|
| 77 |
+
stored on the instance as ``match``, the last value is
|
| 78 |
+
stored as ``last``. ``start_pos`` is the position of the
|
| 79 |
+
pointer before the pattern was matched, ``pos`` is the
|
| 80 |
+
end position.
|
| 81 |
+
"""
|
| 82 |
+
if self.eos:
|
| 83 |
+
raise EndOfText()
|
| 84 |
+
if pattern not in self._re_cache:
|
| 85 |
+
self._re_cache[pattern] = re.compile(pattern, self.flags)
|
| 86 |
+
self.last = self.match
|
| 87 |
+
m = self._re_cache[pattern].match(self.data, self.pos)
|
| 88 |
+
if m is None:
|
| 89 |
+
return False
|
| 90 |
+
self.start_pos = m.start()
|
| 91 |
+
self.pos = m.end()
|
| 92 |
+
self.match = m.group()
|
| 93 |
+
return True
|
| 94 |
+
|
| 95 |
+
def get_char(self):
|
| 96 |
+
"""Scan exactly one char."""
|
| 97 |
+
self.scan('.')
|
| 98 |
+
|
| 99 |
+
def __repr__(self):
|
| 100 |
+
return '<%s %d/%d>' % (
|
| 101 |
+
self.__class__.__name__,
|
| 102 |
+
self.pos,
|
| 103 |
+
self.data_length
|
| 104 |
+
)
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/sphinxext.py
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.sphinxext
|
| 3 |
+
~~~~~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Sphinx extension to generate automatic documentation of lexers,
|
| 6 |
+
formatters and filters.
|
| 7 |
+
|
| 8 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 9 |
+
:license: BSD, see LICENSE for details.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import sys
|
| 13 |
+
|
| 14 |
+
from docutils import nodes
|
| 15 |
+
from docutils.statemachine import ViewList
|
| 16 |
+
from docutils.parsers.rst import Directive
|
| 17 |
+
from sphinx.util.nodes import nested_parse_with_titles
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
MODULEDOC = '''
|
| 21 |
+
.. module:: %s
|
| 22 |
+
|
| 23 |
+
%s
|
| 24 |
+
%s
|
| 25 |
+
'''
|
| 26 |
+
|
| 27 |
+
LEXERDOC = '''
|
| 28 |
+
.. class:: %s
|
| 29 |
+
|
| 30 |
+
:Short names: %s
|
| 31 |
+
:Filenames: %s
|
| 32 |
+
:MIME types: %s
|
| 33 |
+
|
| 34 |
+
%s
|
| 35 |
+
|
| 36 |
+
%s
|
| 37 |
+
|
| 38 |
+
'''
|
| 39 |
+
|
| 40 |
+
FMTERDOC = '''
|
| 41 |
+
.. class:: %s
|
| 42 |
+
|
| 43 |
+
:Short names: %s
|
| 44 |
+
:Filenames: %s
|
| 45 |
+
|
| 46 |
+
%s
|
| 47 |
+
|
| 48 |
+
'''
|
| 49 |
+
|
| 50 |
+
FILTERDOC = '''
|
| 51 |
+
.. class:: %s
|
| 52 |
+
|
| 53 |
+
:Name: %s
|
| 54 |
+
|
| 55 |
+
%s
|
| 56 |
+
|
| 57 |
+
'''
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
class PygmentsDoc(Directive):
|
| 61 |
+
"""
|
| 62 |
+
A directive to collect all lexers/formatters/filters and generate
|
| 63 |
+
autoclass directives for them.
|
| 64 |
+
"""
|
| 65 |
+
has_content = False
|
| 66 |
+
required_arguments = 1
|
| 67 |
+
optional_arguments = 0
|
| 68 |
+
final_argument_whitespace = False
|
| 69 |
+
option_spec = {}
|
| 70 |
+
|
| 71 |
+
def run(self):
|
| 72 |
+
self.filenames = set()
|
| 73 |
+
if self.arguments[0] == 'lexers':
|
| 74 |
+
out = self.document_lexers()
|
| 75 |
+
elif self.arguments[0] == 'formatters':
|
| 76 |
+
out = self.document_formatters()
|
| 77 |
+
elif self.arguments[0] == 'filters':
|
| 78 |
+
out = self.document_filters()
|
| 79 |
+
elif self.arguments[0] == 'lexers_overview':
|
| 80 |
+
out = self.document_lexers_overview()
|
| 81 |
+
else:
|
| 82 |
+
raise Exception('invalid argument for "pygmentsdoc" directive')
|
| 83 |
+
node = nodes.compound()
|
| 84 |
+
vl = ViewList(out.split('\n'), source='')
|
| 85 |
+
nested_parse_with_titles(self.state, vl, node)
|
| 86 |
+
for fn in self.filenames:
|
| 87 |
+
self.state.document.settings.record_dependencies.add(fn)
|
| 88 |
+
return node.children
|
| 89 |
+
|
| 90 |
+
def document_lexers_overview(self):
|
| 91 |
+
"""Generate a tabular overview of all lexers.
|
| 92 |
+
|
| 93 |
+
The columns are the lexer name, the extensions handled by this lexer
|
| 94 |
+
(or "None"), the aliases and a link to the lexer class."""
|
| 95 |
+
from pip._vendor.pygments.lexers._mapping import LEXERS
|
| 96 |
+
from pip._vendor.pygments.lexers import find_lexer_class
|
| 97 |
+
out = []
|
| 98 |
+
|
| 99 |
+
table = []
|
| 100 |
+
|
| 101 |
+
def format_link(name, url):
|
| 102 |
+
if url:
|
| 103 |
+
return f'`{name} <{url}>`_'
|
| 104 |
+
return name
|
| 105 |
+
|
| 106 |
+
for classname, data in sorted(LEXERS.items(), key=lambda x: x[1][1].lower()):
|
| 107 |
+
lexer_cls = find_lexer_class(data[1])
|
| 108 |
+
extensions = lexer_cls.filenames + lexer_cls.alias_filenames
|
| 109 |
+
|
| 110 |
+
table.append({
|
| 111 |
+
'name': format_link(data[1], lexer_cls.url),
|
| 112 |
+
'extensions': ', '.join(extensions).replace('*', '\\*').replace('_', '\\') or 'None',
|
| 113 |
+
'aliases': ', '.join(data[2]),
|
| 114 |
+
'class': f'{data[0]}.{classname}'
|
| 115 |
+
})
|
| 116 |
+
|
| 117 |
+
column_names = ['name', 'extensions', 'aliases', 'class']
|
| 118 |
+
column_lengths = [max([len(row[column]) for row in table if row[column]])
|
| 119 |
+
for column in column_names]
|
| 120 |
+
|
| 121 |
+
def write_row(*columns):
|
| 122 |
+
"""Format a table row"""
|
| 123 |
+
out = []
|
| 124 |
+
for length, col in zip(column_lengths, columns):
|
| 125 |
+
if col:
|
| 126 |
+
out.append(col.ljust(length))
|
| 127 |
+
else:
|
| 128 |
+
out.append(' '*length)
|
| 129 |
+
|
| 130 |
+
return ' '.join(out)
|
| 131 |
+
|
| 132 |
+
def write_seperator():
|
| 133 |
+
"""Write a table separator row"""
|
| 134 |
+
sep = ['='*c for c in column_lengths]
|
| 135 |
+
return write_row(*sep)
|
| 136 |
+
|
| 137 |
+
out.append(write_seperator())
|
| 138 |
+
out.append(write_row('Name', 'Extension(s)', 'Short name(s)', 'Lexer class'))
|
| 139 |
+
out.append(write_seperator())
|
| 140 |
+
for row in table:
|
| 141 |
+
out.append(write_row(
|
| 142 |
+
row['name'],
|
| 143 |
+
row['extensions'],
|
| 144 |
+
row['aliases'],
|
| 145 |
+
f':class:`~{row["class"]}`'))
|
| 146 |
+
out.append(write_seperator())
|
| 147 |
+
|
| 148 |
+
return '\n'.join(out)
|
| 149 |
+
|
| 150 |
+
def document_lexers(self):
|
| 151 |
+
from pip._vendor.pygments.lexers._mapping import LEXERS
|
| 152 |
+
from pip._vendor import pygments
|
| 153 |
+
import inspect
|
| 154 |
+
import pathlib
|
| 155 |
+
|
| 156 |
+
out = []
|
| 157 |
+
modules = {}
|
| 158 |
+
moduledocstrings = {}
|
| 159 |
+
for classname, data in sorted(LEXERS.items(), key=lambda x: x[0]):
|
| 160 |
+
module = data[0]
|
| 161 |
+
mod = __import__(module, None, None, [classname])
|
| 162 |
+
self.filenames.add(mod.__file__)
|
| 163 |
+
cls = getattr(mod, classname)
|
| 164 |
+
if not cls.__doc__:
|
| 165 |
+
print(f"Warning: {classname} does not have a docstring.")
|
| 166 |
+
docstring = cls.__doc__
|
| 167 |
+
if isinstance(docstring, bytes):
|
| 168 |
+
docstring = docstring.decode('utf8')
|
| 169 |
+
|
| 170 |
+
example_file = getattr(cls, '_example', None)
|
| 171 |
+
if example_file:
|
| 172 |
+
p = pathlib.Path(inspect.getabsfile(pygments)).parent.parent /\
|
| 173 |
+
'tests' / 'examplefiles' / example_file
|
| 174 |
+
content = p.read_text(encoding='utf-8')
|
| 175 |
+
if not content:
|
| 176 |
+
raise Exception(
|
| 177 |
+
f"Empty example file '{example_file}' for lexer "
|
| 178 |
+
f"{classname}")
|
| 179 |
+
|
| 180 |
+
if data[2]:
|
| 181 |
+
lexer_name = data[2][0]
|
| 182 |
+
docstring += '\n\n .. admonition:: Example\n'
|
| 183 |
+
docstring += f'\n .. code-block:: {lexer_name}\n\n'
|
| 184 |
+
for line in content.splitlines():
|
| 185 |
+
docstring += f' {line}\n'
|
| 186 |
+
|
| 187 |
+
if cls.version_added:
|
| 188 |
+
version_line = f'.. versionadded:: {cls.version_added}'
|
| 189 |
+
else:
|
| 190 |
+
version_line = ''
|
| 191 |
+
|
| 192 |
+
modules.setdefault(module, []).append((
|
| 193 |
+
classname,
|
| 194 |
+
', '.join(data[2]) or 'None',
|
| 195 |
+
', '.join(data[3]).replace('*', '\\*').replace('_', '\\') or 'None',
|
| 196 |
+
', '.join(data[4]) or 'None',
|
| 197 |
+
docstring,
|
| 198 |
+
version_line))
|
| 199 |
+
if module not in moduledocstrings:
|
| 200 |
+
moddoc = mod.__doc__
|
| 201 |
+
if isinstance(moddoc, bytes):
|
| 202 |
+
moddoc = moddoc.decode('utf8')
|
| 203 |
+
moduledocstrings[module] = moddoc
|
| 204 |
+
|
| 205 |
+
for module, lexers in sorted(modules.items(), key=lambda x: x[0]):
|
| 206 |
+
if moduledocstrings[module] is None:
|
| 207 |
+
raise Exception(f"Missing docstring for {module}")
|
| 208 |
+
heading = moduledocstrings[module].splitlines()[4].strip().rstrip('.')
|
| 209 |
+
out.append(MODULEDOC % (module, heading, '-'*len(heading)))
|
| 210 |
+
for data in lexers:
|
| 211 |
+
out.append(LEXERDOC % data)
|
| 212 |
+
|
| 213 |
+
return ''.join(out)
|
| 214 |
+
|
| 215 |
+
def document_formatters(self):
|
| 216 |
+
from pip._vendor.pygments.formatters import FORMATTERS
|
| 217 |
+
|
| 218 |
+
out = []
|
| 219 |
+
for classname, data in sorted(FORMATTERS.items(), key=lambda x: x[0]):
|
| 220 |
+
module = data[0]
|
| 221 |
+
mod = __import__(module, None, None, [classname])
|
| 222 |
+
self.filenames.add(mod.__file__)
|
| 223 |
+
cls = getattr(mod, classname)
|
| 224 |
+
docstring = cls.__doc__
|
| 225 |
+
if isinstance(docstring, bytes):
|
| 226 |
+
docstring = docstring.decode('utf8')
|
| 227 |
+
heading = cls.__name__
|
| 228 |
+
out.append(FMTERDOC % (heading, ', '.join(data[2]) or 'None',
|
| 229 |
+
', '.join(data[3]).replace('*', '\\*') or 'None',
|
| 230 |
+
docstring))
|
| 231 |
+
return ''.join(out)
|
| 232 |
+
|
| 233 |
+
def document_filters(self):
|
| 234 |
+
from pip._vendor.pygments.filters import FILTERS
|
| 235 |
+
|
| 236 |
+
out = []
|
| 237 |
+
for name, cls in FILTERS.items():
|
| 238 |
+
self.filenames.add(sys.modules[cls.__module__].__file__)
|
| 239 |
+
docstring = cls.__doc__
|
| 240 |
+
if isinstance(docstring, bytes):
|
| 241 |
+
docstring = docstring.decode('utf8')
|
| 242 |
+
out.append(FILTERDOC % (cls.__name__, name, docstring))
|
| 243 |
+
return ''.join(out)
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
def setup(app):
|
| 247 |
+
app.add_directive('pygmentsdoc', PygmentsDoc)
|
.venv/lib/python3.14/site-packages/pip/_vendor/pygments/style.py
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
pygments.style
|
| 3 |
+
~~~~~~~~~~~~~~
|
| 4 |
+
|
| 5 |
+
Basic style object.
|
| 6 |
+
|
| 7 |
+
:copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
|
| 8 |
+
:license: BSD, see LICENSE for details.
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
from pip._vendor.pygments.token import Token, STANDARD_TYPES
|
| 12 |
+
|
| 13 |
+
# Default mapping of ansixxx to RGB colors.
|
| 14 |
+
_ansimap = {
|
| 15 |
+
# dark
|
| 16 |
+
'ansiblack': '000000',
|
| 17 |
+
'ansired': '7f0000',
|
| 18 |
+
'ansigreen': '007f00',
|
| 19 |
+
'ansiyellow': '7f7fe0',
|
| 20 |
+
'ansiblue': '00007f',
|
| 21 |
+
'ansimagenta': '7f007f',
|
| 22 |
+
'ansicyan': '007f7f',
|
| 23 |
+
'ansigray': 'e5e5e5',
|
| 24 |
+
# normal
|
| 25 |
+
'ansibrightblack': '555555',
|
| 26 |
+
'ansibrightred': 'ff0000',
|
| 27 |
+
'ansibrightgreen': '00ff00',
|
| 28 |
+
'ansibrightyellow': 'ffff00',
|
| 29 |
+
'ansibrightblue': '0000ff',
|
| 30 |
+
'ansibrightmagenta': 'ff00ff',
|
| 31 |
+
'ansibrightcyan': '00ffff',
|
| 32 |
+
'ansiwhite': 'ffffff',
|
| 33 |
+
}
|
| 34 |
+
# mapping of deprecated #ansixxx colors to new color names
|
| 35 |
+
_deprecated_ansicolors = {
|
| 36 |
+
# dark
|
| 37 |
+
'#ansiblack': 'ansiblack',
|
| 38 |
+
'#ansidarkred': 'ansired',
|
| 39 |
+
'#ansidarkgreen': 'ansigreen',
|
| 40 |
+
'#ansibrown': 'ansiyellow',
|
| 41 |
+
'#ansidarkblue': 'ansiblue',
|
| 42 |
+
'#ansipurple': 'ansimagenta',
|
| 43 |
+
'#ansiteal': 'ansicyan',
|
| 44 |
+
'#ansilightgray': 'ansigray',
|
| 45 |
+
# normal
|
| 46 |
+
'#ansidarkgray': 'ansibrightblack',
|
| 47 |
+
'#ansired': 'ansibrightred',
|
| 48 |
+
'#ansigreen': 'ansibrightgreen',
|
| 49 |
+
'#ansiyellow': 'ansibrightyellow',
|
| 50 |
+
'#ansiblue': 'ansibrightblue',
|
| 51 |
+
'#ansifuchsia': 'ansibrightmagenta',
|
| 52 |
+
'#ansiturquoise': 'ansibrightcyan',
|
| 53 |
+
'#ansiwhite': 'ansiwhite',
|
| 54 |
+
}
|
| 55 |
+
ansicolors = set(_ansimap)
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
class StyleMeta(type):
|
| 59 |
+
|
| 60 |
+
def __new__(mcs, name, bases, dct):
|
| 61 |
+
obj = type.__new__(mcs, name, bases, dct)
|
| 62 |
+
for token in STANDARD_TYPES:
|
| 63 |
+
if token not in obj.styles:
|
| 64 |
+
obj.styles[token] = ''
|
| 65 |
+
|
| 66 |
+
def colorformat(text):
|
| 67 |
+
if text in ansicolors:
|
| 68 |
+
return text
|
| 69 |
+
if text[0:1] == '#':
|
| 70 |
+
col = text[1:]
|
| 71 |
+
if len(col) == 6:
|
| 72 |
+
return col
|
| 73 |
+
elif len(col) == 3:
|
| 74 |
+
return col[0] * 2 + col[1] * 2 + col[2] * 2
|
| 75 |
+
elif text == '':
|
| 76 |
+
return ''
|
| 77 |
+
elif text.startswith('var') or text.startswith('calc'):
|
| 78 |
+
return text
|
| 79 |
+
assert False, f"wrong color format {text!r}"
|
| 80 |
+
|
| 81 |
+
_styles = obj._styles = {}
|
| 82 |
+
|
| 83 |
+
for ttype in obj.styles:
|
| 84 |
+
for token in ttype.split():
|
| 85 |
+
if token in _styles:
|
| 86 |
+
continue
|
| 87 |
+
ndef = _styles.get(token.parent, None)
|
| 88 |
+
styledefs = obj.styles.get(token, '').split()
|
| 89 |
+
if not ndef or token is None:
|
| 90 |
+
ndef = ['', 0, 0, 0, '', '', 0, 0, 0]
|
| 91 |
+
elif 'noinherit' in styledefs and token is not Token:
|
| 92 |
+
ndef = _styles[Token][:]
|
| 93 |
+
else:
|
| 94 |
+
ndef = ndef[:]
|
| 95 |
+
_styles[token] = ndef
|
| 96 |
+
for styledef in obj.styles.get(token, '').split():
|
| 97 |
+
if styledef == 'noinherit':
|
| 98 |
+
pass
|
| 99 |
+
elif styledef == 'bold':
|
| 100 |
+
ndef[1] = 1
|
| 101 |
+
elif styledef == 'nobold':
|
| 102 |
+
ndef[1] = 0
|
| 103 |
+
elif styledef == 'italic':
|
| 104 |
+
ndef[2] = 1
|
| 105 |
+
elif styledef == 'noitalic':
|
| 106 |
+
ndef[2] = 0
|
| 107 |
+
elif styledef == 'underline':
|
| 108 |
+
ndef[3] = 1
|
| 109 |
+
elif styledef == 'nounderline':
|
| 110 |
+
ndef[3] = 0
|
| 111 |
+
elif styledef[:3] == 'bg:':
|
| 112 |
+
ndef[4] = colorformat(styledef[3:])
|
| 113 |
+
elif styledef[:7] == 'border:':
|
| 114 |
+
ndef[5] = colorformat(styledef[7:])
|
| 115 |
+
elif styledef == 'roman':
|
| 116 |
+
ndef[6] = 1
|
| 117 |
+
elif styledef == 'sans':
|
| 118 |
+
ndef[7] = 1
|
| 119 |
+
elif styledef == 'mono':
|
| 120 |
+
ndef[8] = 1
|
| 121 |
+
else:
|
| 122 |
+
ndef[0] = colorformat(styledef)
|
| 123 |
+
|
| 124 |
+
return obj
|
| 125 |
+
|
| 126 |
+
def style_for_token(cls, token):
|
| 127 |
+
t = cls._styles[token]
|
| 128 |
+
ansicolor = bgansicolor = None
|
| 129 |
+
color = t[0]
|
| 130 |
+
if color in _deprecated_ansicolors:
|
| 131 |
+
color = _deprecated_ansicolors[color]
|
| 132 |
+
if color in ansicolors:
|
| 133 |
+
ansicolor = color
|
| 134 |
+
color = _ansimap[color]
|
| 135 |
+
bgcolor = t[4]
|
| 136 |
+
if bgcolor in _deprecated_ansicolors:
|
| 137 |
+
bgcolor = _deprecated_ansicolors[bgcolor]
|
| 138 |
+
if bgcolor in ansicolors:
|
| 139 |
+
bgansicolor = bgcolor
|
| 140 |
+
bgcolor = _ansimap[bgcolor]
|
| 141 |
+
|
| 142 |
+
return {
|
| 143 |
+
'color': color or None,
|
| 144 |
+
'bold': bool(t[1]),
|
| 145 |
+
'italic': bool(t[2]),
|
| 146 |
+
'underline': bool(t[3]),
|
| 147 |
+
'bgcolor': bgcolor or None,
|
| 148 |
+
'border': t[5] or None,
|
| 149 |
+
'roman': bool(t[6]) or None,
|
| 150 |
+
'sans': bool(t[7]) or None,
|
| 151 |
+
'mono': bool(t[8]) or None,
|
| 152 |
+
'ansicolor': ansicolor,
|
| 153 |
+
'bgansicolor': bgansicolor,
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
def list_styles(cls):
|
| 157 |
+
return list(cls)
|
| 158 |
+
|
| 159 |
+
def styles_token(cls, ttype):
|
| 160 |
+
return ttype in cls._styles
|
| 161 |
+
|
| 162 |
+
def __iter__(cls):
|
| 163 |
+
for token in cls._styles:
|
| 164 |
+
yield token, cls.style_for_token(token)
|
| 165 |
+
|
| 166 |
+
def __len__(cls):
|
| 167 |
+
return len(cls._styles)
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
class Style(metaclass=StyleMeta):
|
| 171 |
+
|
| 172 |
+
#: overall background color (``None`` means transparent)
|
| 173 |
+
background_color = '#ffffff'
|
| 174 |
+
|
| 175 |
+
#: highlight background color
|
| 176 |
+
highlight_color = '#ffffcc'
|
| 177 |
+
|
| 178 |
+
#: line number font color
|
| 179 |
+
line_number_color = 'inherit'
|
| 180 |
+
|
| 181 |
+
#: line number background color
|
| 182 |
+
line_number_background_color = 'transparent'
|
| 183 |
+
|
| 184 |
+
#: special line number font color
|
| 185 |
+
line_number_special_color = '#000000'
|
| 186 |
+
|
| 187 |
+
#: special line number background color
|
| 188 |
+
line_number_special_background_color = '#ffffc0'
|
| 189 |
+
|
| 190 |
+
#: Style definitions for individual token types.
|
| 191 |
+
styles = {}
|
| 192 |
+
|
| 193 |
+
#: user-friendly style name (used when selecting the style, so this
|
| 194 |
+
# should be all-lowercase, no spaces, hyphens)
|
| 195 |
+
name = 'unnamed'
|
| 196 |
+
|
| 197 |
+
aliases = []
|
| 198 |
+
|
| 199 |
+
# Attribute for lexers defined within Pygments. If set
|
| 200 |
+
# to True, the style is not shown in the style gallery
|
| 201 |
+
# on the website. This is intended for language-specific
|
| 202 |
+
# styles.
|
| 203 |
+
web_style_gallery_exclude = False
|