Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .venv/lib/python3.11/site-packages/distro/__init__.py +54 -0
- .venv/lib/python3.11/site-packages/distro/__main__.py +4 -0
- .venv/lib/python3.11/site-packages/distro/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/distro/__pycache__/__main__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/distro/__pycache__/distro.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/distro/distro.py +1403 -0
- .venv/lib/python3.11/site-packages/distro/py.typed +0 -0
- .venv/lib/python3.11/site-packages/gguf-0.10.0.dist-info/INSTALLER +1 -0
- .venv/lib/python3.11/site-packages/gguf-0.10.0.dist-info/LICENSE +21 -0
- .venv/lib/python3.11/site-packages/gguf-0.10.0.dist-info/METADATA +114 -0
- .venv/lib/python3.11/site-packages/gguf-0.10.0.dist-info/RECORD +45 -0
- .venv/lib/python3.11/site-packages/gguf-0.10.0.dist-info/WHEEL +4 -0
- .venv/lib/python3.11/site-packages/gguf-0.10.0.dist-info/entry_points.txt +6 -0
- .venv/lib/python3.11/site-packages/mistral_common/__init__.py +1 -0
- .venv/lib/python3.11/site-packages/mistral_common/base.py +9 -0
- .venv/lib/python3.11/site-packages/mistral_common/exceptions.py +67 -0
- .venv/lib/python3.11/site-packages/mistral_common/multimodal.py +70 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/__init__.py +0 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/__pycache__/base.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/__pycache__/utils.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/base.py +18 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/__init__.py +0 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/__pycache__/normalize.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/__pycache__/request.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/__pycache__/tool_calls.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/__pycache__/validator.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/messages.py +113 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/normalize.py +265 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/request.py +27 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/response.py +66 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/tool_calls.py +51 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/validator.py +328 -0
- .venv/lib/python3.11/site-packages/mistral_common/protocol/utils.py +5 -0
- .venv/lib/python3.11/site-packages/mistral_common/py.typed +0 -0
- .venv/lib/python3.11/site-packages/numpy/polynomial/tests/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/polynomial/tests/__pycache__/test_hermite_e.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/INSTALLER +1 -0
- .venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/LICENSE +201 -0
- .venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/METADATA +238 -0
- .venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/RECORD +0 -0
- .venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/REQUESTED +0 -0
- .venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/WHEEL +5 -0
- .venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/entry_points.txt +2 -0
- .venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/top_level.txt +1 -0
- .venv/lib/python3.11/site-packages/xgrammar/__init__.py +13 -0
- .venv/lib/python3.11/site-packages/xgrammar/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/xgrammar/__pycache__/base.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/xgrammar/__pycache__/compiler.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/xgrammar/__pycache__/grammar.cpython-311.pyc +0 -0
.venv/lib/python3.11/site-packages/distro/__init__.py
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from .distro import (
|
2 |
+
NORMALIZED_DISTRO_ID,
|
3 |
+
NORMALIZED_LSB_ID,
|
4 |
+
NORMALIZED_OS_ID,
|
5 |
+
LinuxDistribution,
|
6 |
+
__version__,
|
7 |
+
build_number,
|
8 |
+
codename,
|
9 |
+
distro_release_attr,
|
10 |
+
distro_release_info,
|
11 |
+
id,
|
12 |
+
info,
|
13 |
+
like,
|
14 |
+
linux_distribution,
|
15 |
+
lsb_release_attr,
|
16 |
+
lsb_release_info,
|
17 |
+
major_version,
|
18 |
+
minor_version,
|
19 |
+
name,
|
20 |
+
os_release_attr,
|
21 |
+
os_release_info,
|
22 |
+
uname_attr,
|
23 |
+
uname_info,
|
24 |
+
version,
|
25 |
+
version_parts,
|
26 |
+
)
|
27 |
+
|
28 |
+
__all__ = [
|
29 |
+
"NORMALIZED_DISTRO_ID",
|
30 |
+
"NORMALIZED_LSB_ID",
|
31 |
+
"NORMALIZED_OS_ID",
|
32 |
+
"LinuxDistribution",
|
33 |
+
"build_number",
|
34 |
+
"codename",
|
35 |
+
"distro_release_attr",
|
36 |
+
"distro_release_info",
|
37 |
+
"id",
|
38 |
+
"info",
|
39 |
+
"like",
|
40 |
+
"linux_distribution",
|
41 |
+
"lsb_release_attr",
|
42 |
+
"lsb_release_info",
|
43 |
+
"major_version",
|
44 |
+
"minor_version",
|
45 |
+
"name",
|
46 |
+
"os_release_attr",
|
47 |
+
"os_release_info",
|
48 |
+
"uname_attr",
|
49 |
+
"uname_info",
|
50 |
+
"version",
|
51 |
+
"version_parts",
|
52 |
+
]
|
53 |
+
|
54 |
+
__version__ = __version__
|
.venv/lib/python3.11/site-packages/distro/__main__.py
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from .distro import main
|
2 |
+
|
3 |
+
if __name__ == "__main__":
|
4 |
+
main()
|
.venv/lib/python3.11/site-packages/distro/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (1.18 kB). View file
|
|
.venv/lib/python3.11/site-packages/distro/__pycache__/__main__.cpython-311.pyc
ADDED
Binary file (312 Bytes). View file
|
|
.venv/lib/python3.11/site-packages/distro/__pycache__/distro.cpython-311.pyc
ADDED
Binary file (57.8 kB). View file
|
|
.venv/lib/python3.11/site-packages/distro/distro.py
ADDED
@@ -0,0 +1,1403 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
+
# Copyright 2015-2021 Nir Cohen
|
3 |
+
#
|
4 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5 |
+
# you may not use this file except in compliance with the License.
|
6 |
+
# You may obtain a copy of the License at
|
7 |
+
#
|
8 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9 |
+
#
|
10 |
+
# Unless required by applicable law or agreed to in writing, software
|
11 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13 |
+
# See the License for the specific language governing permissions and
|
14 |
+
# limitations under the License.
|
15 |
+
|
16 |
+
"""
|
17 |
+
The ``distro`` package (``distro`` stands for Linux Distribution) provides
|
18 |
+
information about the Linux distribution it runs on, such as a reliable
|
19 |
+
machine-readable distro ID, or version information.
|
20 |
+
|
21 |
+
It is the recommended replacement for Python's original
|
22 |
+
:py:func:`platform.linux_distribution` function, but it provides much more
|
23 |
+
functionality. An alternative implementation became necessary because Python
|
24 |
+
3.5 deprecated this function, and Python 3.8 removed it altogether. Its
|
25 |
+
predecessor function :py:func:`platform.dist` was already deprecated since
|
26 |
+
Python 2.6 and removed in Python 3.8. Still, there are many cases in which
|
27 |
+
access to OS distribution information is needed. See `Python issue 1322
|
28 |
+
<https://bugs.python.org/issue1322>`_ for more information.
|
29 |
+
"""
|
30 |
+
|
31 |
+
import argparse
|
32 |
+
import json
|
33 |
+
import logging
|
34 |
+
import os
|
35 |
+
import re
|
36 |
+
import shlex
|
37 |
+
import subprocess
|
38 |
+
import sys
|
39 |
+
import warnings
|
40 |
+
from typing import (
|
41 |
+
Any,
|
42 |
+
Callable,
|
43 |
+
Dict,
|
44 |
+
Iterable,
|
45 |
+
Optional,
|
46 |
+
Sequence,
|
47 |
+
TextIO,
|
48 |
+
Tuple,
|
49 |
+
Type,
|
50 |
+
)
|
51 |
+
|
52 |
+
try:
|
53 |
+
from typing import TypedDict
|
54 |
+
except ImportError:
|
55 |
+
# Python 3.7
|
56 |
+
TypedDict = dict
|
57 |
+
|
58 |
+
__version__ = "1.9.0"
|
59 |
+
|
60 |
+
|
61 |
+
class VersionDict(TypedDict):
|
62 |
+
major: str
|
63 |
+
minor: str
|
64 |
+
build_number: str
|
65 |
+
|
66 |
+
|
67 |
+
class InfoDict(TypedDict):
|
68 |
+
id: str
|
69 |
+
version: str
|
70 |
+
version_parts: VersionDict
|
71 |
+
like: str
|
72 |
+
codename: str
|
73 |
+
|
74 |
+
|
75 |
+
_UNIXCONFDIR = os.environ.get("UNIXCONFDIR", "/etc")
|
76 |
+
_UNIXUSRLIBDIR = os.environ.get("UNIXUSRLIBDIR", "/usr/lib")
|
77 |
+
_OS_RELEASE_BASENAME = "os-release"
|
78 |
+
|
79 |
+
#: Translation table for normalizing the "ID" attribute defined in os-release
|
80 |
+
#: files, for use by the :func:`distro.id` method.
|
81 |
+
#:
|
82 |
+
#: * Key: Value as defined in the os-release file, translated to lower case,
|
83 |
+
#: with blanks translated to underscores.
|
84 |
+
#:
|
85 |
+
#: * Value: Normalized value.
|
86 |
+
NORMALIZED_OS_ID = {
|
87 |
+
"ol": "oracle", # Oracle Linux
|
88 |
+
"opensuse-leap": "opensuse", # Newer versions of OpenSuSE report as opensuse-leap
|
89 |
+
}
|
90 |
+
|
91 |
+
#: Translation table for normalizing the "Distributor ID" attribute returned by
|
92 |
+
#: the lsb_release command, for use by the :func:`distro.id` method.
|
93 |
+
#:
|
94 |
+
#: * Key: Value as returned by the lsb_release command, translated to lower
|
95 |
+
#: case, with blanks translated to underscores.
|
96 |
+
#:
|
97 |
+
#: * Value: Normalized value.
|
98 |
+
NORMALIZED_LSB_ID = {
|
99 |
+
"enterpriseenterpriseas": "oracle", # Oracle Enterprise Linux 4
|
100 |
+
"enterpriseenterpriseserver": "oracle", # Oracle Linux 5
|
101 |
+
"redhatenterpriseworkstation": "rhel", # RHEL 6, 7 Workstation
|
102 |
+
"redhatenterpriseserver": "rhel", # RHEL 6, 7 Server
|
103 |
+
"redhatenterprisecomputenode": "rhel", # RHEL 6 ComputeNode
|
104 |
+
}
|
105 |
+
|
106 |
+
#: Translation table for normalizing the distro ID derived from the file name
|
107 |
+
#: of distro release files, for use by the :func:`distro.id` method.
|
108 |
+
#:
|
109 |
+
#: * Key: Value as derived from the file name of a distro release file,
|
110 |
+
#: translated to lower case, with blanks translated to underscores.
|
111 |
+
#:
|
112 |
+
#: * Value: Normalized value.
|
113 |
+
NORMALIZED_DISTRO_ID = {
|
114 |
+
"redhat": "rhel", # RHEL 6.x, 7.x
|
115 |
+
}
|
116 |
+
|
117 |
+
# Pattern for content of distro release file (reversed)
|
118 |
+
_DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile(
|
119 |
+
r"(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)"
|
120 |
+
)
|
121 |
+
|
122 |
+
# Pattern for base file name of distro release file
|
123 |
+
_DISTRO_RELEASE_BASENAME_PATTERN = re.compile(r"(\w+)[-_](release|version)$")
|
124 |
+
|
125 |
+
# Base file names to be looked up for if _UNIXCONFDIR is not readable.
|
126 |
+
_DISTRO_RELEASE_BASENAMES = [
|
127 |
+
"SuSE-release",
|
128 |
+
"altlinux-release",
|
129 |
+
"arch-release",
|
130 |
+
"base-release",
|
131 |
+
"centos-release",
|
132 |
+
"fedora-release",
|
133 |
+
"gentoo-release",
|
134 |
+
"mageia-release",
|
135 |
+
"mandrake-release",
|
136 |
+
"mandriva-release",
|
137 |
+
"mandrivalinux-release",
|
138 |
+
"manjaro-release",
|
139 |
+
"oracle-release",
|
140 |
+
"redhat-release",
|
141 |
+
"rocky-release",
|
142 |
+
"sl-release",
|
143 |
+
"slackware-version",
|
144 |
+
]
|
145 |
+
|
146 |
+
# Base file names to be ignored when searching for distro release file
|
147 |
+
_DISTRO_RELEASE_IGNORE_BASENAMES = (
|
148 |
+
"debian_version",
|
149 |
+
"lsb-release",
|
150 |
+
"oem-release",
|
151 |
+
_OS_RELEASE_BASENAME,
|
152 |
+
"system-release",
|
153 |
+
"plesk-release",
|
154 |
+
"iredmail-release",
|
155 |
+
"board-release",
|
156 |
+
"ec2_version",
|
157 |
+
)
|
158 |
+
|
159 |
+
|
160 |
+
def linux_distribution(full_distribution_name: bool = True) -> Tuple[str, str, str]:
|
161 |
+
"""
|
162 |
+
.. deprecated:: 1.6.0
|
163 |
+
|
164 |
+
:func:`distro.linux_distribution()` is deprecated. It should only be
|
165 |
+
used as a compatibility shim with Python's
|
166 |
+
:py:func:`platform.linux_distribution()`. Please use :func:`distro.id`,
|
167 |
+
:func:`distro.version` and :func:`distro.name` instead.
|
168 |
+
|
169 |
+
Return information about the current OS distribution as a tuple
|
170 |
+
``(id_name, version, codename)`` with items as follows:
|
171 |
+
|
172 |
+
* ``id_name``: If *full_distribution_name* is false, the result of
|
173 |
+
:func:`distro.id`. Otherwise, the result of :func:`distro.name`.
|
174 |
+
|
175 |
+
* ``version``: The result of :func:`distro.version`.
|
176 |
+
|
177 |
+
* ``codename``: The extra item (usually in parentheses) after the
|
178 |
+
os-release version number, or the result of :func:`distro.codename`.
|
179 |
+
|
180 |
+
The interface of this function is compatible with the original
|
181 |
+
:py:func:`platform.linux_distribution` function, supporting a subset of
|
182 |
+
its parameters.
|
183 |
+
|
184 |
+
The data it returns may not exactly be the same, because it uses more data
|
185 |
+
sources than the original function, and that may lead to different data if
|
186 |
+
the OS distribution is not consistent across multiple data sources it
|
187 |
+
provides (there are indeed such distributions ...).
|
188 |
+
|
189 |
+
Another reason for differences is the fact that the :func:`distro.id`
|
190 |
+
method normalizes the distro ID string to a reliable machine-readable value
|
191 |
+
for a number of popular OS distributions.
|
192 |
+
"""
|
193 |
+
warnings.warn(
|
194 |
+
"distro.linux_distribution() is deprecated. It should only be used as a "
|
195 |
+
"compatibility shim with Python's platform.linux_distribution(). Please use "
|
196 |
+
"distro.id(), distro.version() and distro.name() instead.",
|
197 |
+
DeprecationWarning,
|
198 |
+
stacklevel=2,
|
199 |
+
)
|
200 |
+
return _distro.linux_distribution(full_distribution_name)
|
201 |
+
|
202 |
+
|
203 |
+
def id() -> str:
|
204 |
+
"""
|
205 |
+
Return the distro ID of the current distribution, as a
|
206 |
+
machine-readable string.
|
207 |
+
|
208 |
+
For a number of OS distributions, the returned distro ID value is
|
209 |
+
*reliable*, in the sense that it is documented and that it does not change
|
210 |
+
across releases of the distribution.
|
211 |
+
|
212 |
+
This package maintains the following reliable distro ID values:
|
213 |
+
|
214 |
+
============== =========================================
|
215 |
+
Distro ID Distribution
|
216 |
+
============== =========================================
|
217 |
+
"ubuntu" Ubuntu
|
218 |
+
"debian" Debian
|
219 |
+
"rhel" RedHat Enterprise Linux
|
220 |
+
"centos" CentOS
|
221 |
+
"fedora" Fedora
|
222 |
+
"sles" SUSE Linux Enterprise Server
|
223 |
+
"opensuse" openSUSE
|
224 |
+
"amzn" Amazon Linux
|
225 |
+
"arch" Arch Linux
|
226 |
+
"buildroot" Buildroot
|
227 |
+
"cloudlinux" CloudLinux OS
|
228 |
+
"exherbo" Exherbo Linux
|
229 |
+
"gentoo" GenToo Linux
|
230 |
+
"ibm_powerkvm" IBM PowerKVM
|
231 |
+
"kvmibm" KVM for IBM z Systems
|
232 |
+
"linuxmint" Linux Mint
|
233 |
+
"mageia" Mageia
|
234 |
+
"mandriva" Mandriva Linux
|
235 |
+
"parallels" Parallels
|
236 |
+
"pidora" Pidora
|
237 |
+
"raspbian" Raspbian
|
238 |
+
"oracle" Oracle Linux (and Oracle Enterprise Linux)
|
239 |
+
"scientific" Scientific Linux
|
240 |
+
"slackware" Slackware
|
241 |
+
"xenserver" XenServer
|
242 |
+
"openbsd" OpenBSD
|
243 |
+
"netbsd" NetBSD
|
244 |
+
"freebsd" FreeBSD
|
245 |
+
"midnightbsd" MidnightBSD
|
246 |
+
"rocky" Rocky Linux
|
247 |
+
"aix" AIX
|
248 |
+
"guix" Guix System
|
249 |
+
"altlinux" ALT Linux
|
250 |
+
============== =========================================
|
251 |
+
|
252 |
+
If you have a need to get distros for reliable IDs added into this set,
|
253 |
+
or if you find that the :func:`distro.id` function returns a different
|
254 |
+
distro ID for one of the listed distros, please create an issue in the
|
255 |
+
`distro issue tracker`_.
|
256 |
+
|
257 |
+
**Lookup hierarchy and transformations:**
|
258 |
+
|
259 |
+
First, the ID is obtained from the following sources, in the specified
|
260 |
+
order. The first available and non-empty value is used:
|
261 |
+
|
262 |
+
* the value of the "ID" attribute of the os-release file,
|
263 |
+
|
264 |
+
* the value of the "Distributor ID" attribute returned by the lsb_release
|
265 |
+
command,
|
266 |
+
|
267 |
+
* the first part of the file name of the distro release file,
|
268 |
+
|
269 |
+
The so determined ID value then passes the following transformations,
|
270 |
+
before it is returned by this method:
|
271 |
+
|
272 |
+
* it is translated to lower case,
|
273 |
+
|
274 |
+
* blanks (which should not be there anyway) are translated to underscores,
|
275 |
+
|
276 |
+
* a normalization of the ID is performed, based upon
|
277 |
+
`normalization tables`_. The purpose of this normalization is to ensure
|
278 |
+
that the ID is as reliable as possible, even across incompatible changes
|
279 |
+
in the OS distributions. A common reason for an incompatible change is
|
280 |
+
the addition of an os-release file, or the addition of the lsb_release
|
281 |
+
command, with ID values that differ from what was previously determined
|
282 |
+
from the distro release file name.
|
283 |
+
"""
|
284 |
+
return _distro.id()
|
285 |
+
|
286 |
+
|
287 |
+
def name(pretty: bool = False) -> str:
|
288 |
+
"""
|
289 |
+
Return the name of the current OS distribution, as a human-readable
|
290 |
+
string.
|
291 |
+
|
292 |
+
If *pretty* is false, the name is returned without version or codename.
|
293 |
+
(e.g. "CentOS Linux")
|
294 |
+
|
295 |
+
If *pretty* is true, the version and codename are appended.
|
296 |
+
(e.g. "CentOS Linux 7.1.1503 (Core)")
|
297 |
+
|
298 |
+
**Lookup hierarchy:**
|
299 |
+
|
300 |
+
The name is obtained from the following sources, in the specified order.
|
301 |
+
The first available and non-empty value is used:
|
302 |
+
|
303 |
+
* If *pretty* is false:
|
304 |
+
|
305 |
+
- the value of the "NAME" attribute of the os-release file,
|
306 |
+
|
307 |
+
- the value of the "Distributor ID" attribute returned by the lsb_release
|
308 |
+
command,
|
309 |
+
|
310 |
+
- the value of the "<name>" field of the distro release file.
|
311 |
+
|
312 |
+
* If *pretty* is true:
|
313 |
+
|
314 |
+
- the value of the "PRETTY_NAME" attribute of the os-release file,
|
315 |
+
|
316 |
+
- the value of the "Description" attribute returned by the lsb_release
|
317 |
+
command,
|
318 |
+
|
319 |
+
- the value of the "<name>" field of the distro release file, appended
|
320 |
+
with the value of the pretty version ("<version_id>" and "<codename>"
|
321 |
+
fields) of the distro release file, if available.
|
322 |
+
"""
|
323 |
+
return _distro.name(pretty)
|
324 |
+
|
325 |
+
|
326 |
+
def version(pretty: bool = False, best: bool = False) -> str:
|
327 |
+
"""
|
328 |
+
Return the version of the current OS distribution, as a human-readable
|
329 |
+
string.
|
330 |
+
|
331 |
+
If *pretty* is false, the version is returned without codename (e.g.
|
332 |
+
"7.0").
|
333 |
+
|
334 |
+
If *pretty* is true, the codename in parenthesis is appended, if the
|
335 |
+
codename is non-empty (e.g. "7.0 (Maipo)").
|
336 |
+
|
337 |
+
Some distributions provide version numbers with different precisions in
|
338 |
+
the different sources of distribution information. Examining the different
|
339 |
+
sources in a fixed priority order does not always yield the most precise
|
340 |
+
version (e.g. for Debian 8.2, or CentOS 7.1).
|
341 |
+
|
342 |
+
Some other distributions may not provide this kind of information. In these
|
343 |
+
cases, an empty string would be returned. This behavior can be observed
|
344 |
+
with rolling releases distributions (e.g. Arch Linux).
|
345 |
+
|
346 |
+
The *best* parameter can be used to control the approach for the returned
|
347 |
+
version:
|
348 |
+
|
349 |
+
If *best* is false, the first non-empty version number in priority order of
|
350 |
+
the examined sources is returned.
|
351 |
+
|
352 |
+
If *best* is true, the most precise version number out of all examined
|
353 |
+
sources is returned.
|
354 |
+
|
355 |
+
**Lookup hierarchy:**
|
356 |
+
|
357 |
+
In all cases, the version number is obtained from the following sources.
|
358 |
+
If *best* is false, this order represents the priority order:
|
359 |
+
|
360 |
+
* the value of the "VERSION_ID" attribute of the os-release file,
|
361 |
+
* the value of the "Release" attribute returned by the lsb_release
|
362 |
+
command,
|
363 |
+
* the version number parsed from the "<version_id>" field of the first line
|
364 |
+
of the distro release file,
|
365 |
+
* the version number parsed from the "PRETTY_NAME" attribute of the
|
366 |
+
os-release file, if it follows the format of the distro release files.
|
367 |
+
* the version number parsed from the "Description" attribute returned by
|
368 |
+
the lsb_release command, if it follows the format of the distro release
|
369 |
+
files.
|
370 |
+
"""
|
371 |
+
return _distro.version(pretty, best)
|
372 |
+
|
373 |
+
|
374 |
+
def version_parts(best: bool = False) -> Tuple[str, str, str]:
|
375 |
+
"""
|
376 |
+
Return the version of the current OS distribution as a tuple
|
377 |
+
``(major, minor, build_number)`` with items as follows:
|
378 |
+
|
379 |
+
* ``major``: The result of :func:`distro.major_version`.
|
380 |
+
|
381 |
+
* ``minor``: The result of :func:`distro.minor_version`.
|
382 |
+
|
383 |
+
* ``build_number``: The result of :func:`distro.build_number`.
|
384 |
+
|
385 |
+
For a description of the *best* parameter, see the :func:`distro.version`
|
386 |
+
method.
|
387 |
+
"""
|
388 |
+
return _distro.version_parts(best)
|
389 |
+
|
390 |
+
|
391 |
+
def major_version(best: bool = False) -> str:
|
392 |
+
"""
|
393 |
+
Return the major version of the current OS distribution, as a string,
|
394 |
+
if provided.
|
395 |
+
Otherwise, the empty string is returned. The major version is the first
|
396 |
+
part of the dot-separated version string.
|
397 |
+
|
398 |
+
For a description of the *best* parameter, see the :func:`distro.version`
|
399 |
+
method.
|
400 |
+
"""
|
401 |
+
return _distro.major_version(best)
|
402 |
+
|
403 |
+
|
404 |
+
def minor_version(best: bool = False) -> str:
|
405 |
+
"""
|
406 |
+
Return the minor version of the current OS distribution, as a string,
|
407 |
+
if provided.
|
408 |
+
Otherwise, the empty string is returned. The minor version is the second
|
409 |
+
part of the dot-separated version string.
|
410 |
+
|
411 |
+
For a description of the *best* parameter, see the :func:`distro.version`
|
412 |
+
method.
|
413 |
+
"""
|
414 |
+
return _distro.minor_version(best)
|
415 |
+
|
416 |
+
|
417 |
+
def build_number(best: bool = False) -> str:
|
418 |
+
"""
|
419 |
+
Return the build number of the current OS distribution, as a string,
|
420 |
+
if provided.
|
421 |
+
Otherwise, the empty string is returned. The build number is the third part
|
422 |
+
of the dot-separated version string.
|
423 |
+
|
424 |
+
For a description of the *best* parameter, see the :func:`distro.version`
|
425 |
+
method.
|
426 |
+
"""
|
427 |
+
return _distro.build_number(best)
|
428 |
+
|
429 |
+
|
430 |
+
def like() -> str:
|
431 |
+
"""
|
432 |
+
Return a space-separated list of distro IDs of distributions that are
|
433 |
+
closely related to the current OS distribution in regards to packaging
|
434 |
+
and programming interfaces, for example distributions the current
|
435 |
+
distribution is a derivative from.
|
436 |
+
|
437 |
+
**Lookup hierarchy:**
|
438 |
+
|
439 |
+
This information item is only provided by the os-release file.
|
440 |
+
For details, see the description of the "ID_LIKE" attribute in the
|
441 |
+
`os-release man page
|
442 |
+
<http://www.freedesktop.org/software/systemd/man/os-release.html>`_.
|
443 |
+
"""
|
444 |
+
return _distro.like()
|
445 |
+
|
446 |
+
|
447 |
+
def codename() -> str:
|
448 |
+
"""
|
449 |
+
Return the codename for the release of the current OS distribution,
|
450 |
+
as a string.
|
451 |
+
|
452 |
+
If the distribution does not have a codename, an empty string is returned.
|
453 |
+
|
454 |
+
Note that the returned codename is not always really a codename. For
|
455 |
+
example, openSUSE returns "x86_64". This function does not handle such
|
456 |
+
cases in any special way and just returns the string it finds, if any.
|
457 |
+
|
458 |
+
**Lookup hierarchy:**
|
459 |
+
|
460 |
+
* the codename within the "VERSION" attribute of the os-release file, if
|
461 |
+
provided,
|
462 |
+
|
463 |
+
* the value of the "Codename" attribute returned by the lsb_release
|
464 |
+
command,
|
465 |
+
|
466 |
+
* the value of the "<codename>" field of the distro release file.
|
467 |
+
"""
|
468 |
+
return _distro.codename()
|
469 |
+
|
470 |
+
|
471 |
+
def info(pretty: bool = False, best: bool = False) -> InfoDict:
|
472 |
+
"""
|
473 |
+
Return certain machine-readable information items about the current OS
|
474 |
+
distribution in a dictionary, as shown in the following example:
|
475 |
+
|
476 |
+
.. sourcecode:: python
|
477 |
+
|
478 |
+
{
|
479 |
+
'id': 'rhel',
|
480 |
+
'version': '7.0',
|
481 |
+
'version_parts': {
|
482 |
+
'major': '7',
|
483 |
+
'minor': '0',
|
484 |
+
'build_number': ''
|
485 |
+
},
|
486 |
+
'like': 'fedora',
|
487 |
+
'codename': 'Maipo'
|
488 |
+
}
|
489 |
+
|
490 |
+
The dictionary structure and keys are always the same, regardless of which
|
491 |
+
information items are available in the underlying data sources. The values
|
492 |
+
for the various keys are as follows:
|
493 |
+
|
494 |
+
* ``id``: The result of :func:`distro.id`.
|
495 |
+
|
496 |
+
* ``version``: The result of :func:`distro.version`.
|
497 |
+
|
498 |
+
* ``version_parts -> major``: The result of :func:`distro.major_version`.
|
499 |
+
|
500 |
+
* ``version_parts -> minor``: The result of :func:`distro.minor_version`.
|
501 |
+
|
502 |
+
* ``version_parts -> build_number``: The result of
|
503 |
+
:func:`distro.build_number`.
|
504 |
+
|
505 |
+
* ``like``: The result of :func:`distro.like`.
|
506 |
+
|
507 |
+
* ``codename``: The result of :func:`distro.codename`.
|
508 |
+
|
509 |
+
For a description of the *pretty* and *best* parameters, see the
|
510 |
+
:func:`distro.version` method.
|
511 |
+
"""
|
512 |
+
return _distro.info(pretty, best)
|
513 |
+
|
514 |
+
|
515 |
+
def os_release_info() -> Dict[str, str]:
|
516 |
+
"""
|
517 |
+
Return a dictionary containing key-value pairs for the information items
|
518 |
+
from the os-release file data source of the current OS distribution.
|
519 |
+
|
520 |
+
See `os-release file`_ for details about these information items.
|
521 |
+
"""
|
522 |
+
return _distro.os_release_info()
|
523 |
+
|
524 |
+
|
525 |
+
def lsb_release_info() -> Dict[str, str]:
|
526 |
+
"""
|
527 |
+
Return a dictionary containing key-value pairs for the information items
|
528 |
+
from the lsb_release command data source of the current OS distribution.
|
529 |
+
|
530 |
+
See `lsb_release command output`_ for details about these information
|
531 |
+
items.
|
532 |
+
"""
|
533 |
+
return _distro.lsb_release_info()
|
534 |
+
|
535 |
+
|
536 |
+
def distro_release_info() -> Dict[str, str]:
|
537 |
+
"""
|
538 |
+
Return a dictionary containing key-value pairs for the information items
|
539 |
+
from the distro release file data source of the current OS distribution.
|
540 |
+
|
541 |
+
See `distro release file`_ for details about these information items.
|
542 |
+
"""
|
543 |
+
return _distro.distro_release_info()
|
544 |
+
|
545 |
+
|
546 |
+
def uname_info() -> Dict[str, str]:
|
547 |
+
"""
|
548 |
+
Return a dictionary containing key-value pairs for the information items
|
549 |
+
from the distro release file data source of the current OS distribution.
|
550 |
+
"""
|
551 |
+
return _distro.uname_info()
|
552 |
+
|
553 |
+
|
554 |
+
def os_release_attr(attribute: str) -> str:
|
555 |
+
"""
|
556 |
+
Return a single named information item from the os-release file data source
|
557 |
+
of the current OS distribution.
|
558 |
+
|
559 |
+
Parameters:
|
560 |
+
|
561 |
+
* ``attribute`` (string): Key of the information item.
|
562 |
+
|
563 |
+
Returns:
|
564 |
+
|
565 |
+
* (string): Value of the information item, if the item exists.
|
566 |
+
The empty string, if the item does not exist.
|
567 |
+
|
568 |
+
See `os-release file`_ for details about these information items.
|
569 |
+
"""
|
570 |
+
return _distro.os_release_attr(attribute)
|
571 |
+
|
572 |
+
|
573 |
+
def lsb_release_attr(attribute: str) -> str:
|
574 |
+
"""
|
575 |
+
Return a single named information item from the lsb_release command output
|
576 |
+
data source of the current OS distribution.
|
577 |
+
|
578 |
+
Parameters:
|
579 |
+
|
580 |
+
* ``attribute`` (string): Key of the information item.
|
581 |
+
|
582 |
+
Returns:
|
583 |
+
|
584 |
+
* (string): Value of the information item, if the item exists.
|
585 |
+
The empty string, if the item does not exist.
|
586 |
+
|
587 |
+
See `lsb_release command output`_ for details about these information
|
588 |
+
items.
|
589 |
+
"""
|
590 |
+
return _distro.lsb_release_attr(attribute)
|
591 |
+
|
592 |
+
|
593 |
+
def distro_release_attr(attribute: str) -> str:
|
594 |
+
"""
|
595 |
+
Return a single named information item from the distro release file
|
596 |
+
data source of the current OS distribution.
|
597 |
+
|
598 |
+
Parameters:
|
599 |
+
|
600 |
+
* ``attribute`` (string): Key of the information item.
|
601 |
+
|
602 |
+
Returns:
|
603 |
+
|
604 |
+
* (string): Value of the information item, if the item exists.
|
605 |
+
The empty string, if the item does not exist.
|
606 |
+
|
607 |
+
See `distro release file`_ for details about these information items.
|
608 |
+
"""
|
609 |
+
return _distro.distro_release_attr(attribute)
|
610 |
+
|
611 |
+
|
612 |
+
def uname_attr(attribute: str) -> str:
|
613 |
+
"""
|
614 |
+
Return a single named information item from the distro release file
|
615 |
+
data source of the current OS distribution.
|
616 |
+
|
617 |
+
Parameters:
|
618 |
+
|
619 |
+
* ``attribute`` (string): Key of the information item.
|
620 |
+
|
621 |
+
Returns:
|
622 |
+
|
623 |
+
* (string): Value of the information item, if the item exists.
|
624 |
+
The empty string, if the item does not exist.
|
625 |
+
"""
|
626 |
+
return _distro.uname_attr(attribute)
|
627 |
+
|
628 |
+
|
629 |
+
try:
|
630 |
+
from functools import cached_property
|
631 |
+
except ImportError:
|
632 |
+
# Python < 3.8
|
633 |
+
class cached_property: # type: ignore
|
634 |
+
"""A version of @property which caches the value. On access, it calls the
|
635 |
+
underlying function and sets the value in `__dict__` so future accesses
|
636 |
+
will not re-call the property.
|
637 |
+
"""
|
638 |
+
|
639 |
+
def __init__(self, f: Callable[[Any], Any]) -> None:
|
640 |
+
self._fname = f.__name__
|
641 |
+
self._f = f
|
642 |
+
|
643 |
+
def __get__(self, obj: Any, owner: Type[Any]) -> Any:
|
644 |
+
assert obj is not None, f"call {self._fname} on an instance"
|
645 |
+
ret = obj.__dict__[self._fname] = self._f(obj)
|
646 |
+
return ret
|
647 |
+
|
648 |
+
|
649 |
+
class LinuxDistribution:
|
650 |
+
"""
|
651 |
+
Provides information about a OS distribution.
|
652 |
+
|
653 |
+
This package creates a private module-global instance of this class with
|
654 |
+
default initialization arguments, that is used by the
|
655 |
+
`consolidated accessor functions`_ and `single source accessor functions`_.
|
656 |
+
By using default initialization arguments, that module-global instance
|
657 |
+
returns data about the current OS distribution (i.e. the distro this
|
658 |
+
package runs on).
|
659 |
+
|
660 |
+
Normally, it is not necessary to create additional instances of this class.
|
661 |
+
However, in situations where control is needed over the exact data sources
|
662 |
+
that are used, instances of this class can be created with a specific
|
663 |
+
distro release file, or a specific os-release file, or without invoking the
|
664 |
+
lsb_release command.
|
665 |
+
"""
|
666 |
+
|
667 |
+
def __init__(
|
668 |
+
self,
|
669 |
+
include_lsb: Optional[bool] = None,
|
670 |
+
os_release_file: str = "",
|
671 |
+
distro_release_file: str = "",
|
672 |
+
include_uname: Optional[bool] = None,
|
673 |
+
root_dir: Optional[str] = None,
|
674 |
+
include_oslevel: Optional[bool] = None,
|
675 |
+
) -> None:
|
676 |
+
"""
|
677 |
+
The initialization method of this class gathers information from the
|
678 |
+
available data sources, and stores that in private instance attributes.
|
679 |
+
Subsequent access to the information items uses these private instance
|
680 |
+
attributes, so that the data sources are read only once.
|
681 |
+
|
682 |
+
Parameters:
|
683 |
+
|
684 |
+
* ``include_lsb`` (bool): Controls whether the
|
685 |
+
`lsb_release command output`_ is included as a data source.
|
686 |
+
|
687 |
+
If the lsb_release command is not available in the program execution
|
688 |
+
path, the data source for the lsb_release command will be empty.
|
689 |
+
|
690 |
+
* ``os_release_file`` (string): The path name of the
|
691 |
+
`os-release file`_ that is to be used as a data source.
|
692 |
+
|
693 |
+
An empty string (the default) will cause the default path name to
|
694 |
+
be used (see `os-release file`_ for details).
|
695 |
+
|
696 |
+
If the specified or defaulted os-release file does not exist, the
|
697 |
+
data source for the os-release file will be empty.
|
698 |
+
|
699 |
+
* ``distro_release_file`` (string): The path name of the
|
700 |
+
`distro release file`_ that is to be used as a data source.
|
701 |
+
|
702 |
+
An empty string (the default) will cause a default search algorithm
|
703 |
+
to be used (see `distro release file`_ for details).
|
704 |
+
|
705 |
+
If the specified distro release file does not exist, or if no default
|
706 |
+
distro release file can be found, the data source for the distro
|
707 |
+
release file will be empty.
|
708 |
+
|
709 |
+
* ``include_uname`` (bool): Controls whether uname command output is
|
710 |
+
included as a data source. If the uname command is not available in
|
711 |
+
the program execution path the data source for the uname command will
|
712 |
+
be empty.
|
713 |
+
|
714 |
+
* ``root_dir`` (string): The absolute path to the root directory to use
|
715 |
+
to find distro-related information files. Note that ``include_*``
|
716 |
+
parameters must not be enabled in combination with ``root_dir``.
|
717 |
+
|
718 |
+
* ``include_oslevel`` (bool): Controls whether (AIX) oslevel command
|
719 |
+
output is included as a data source. If the oslevel command is not
|
720 |
+
available in the program execution path the data source will be
|
721 |
+
empty.
|
722 |
+
|
723 |
+
Public instance attributes:
|
724 |
+
|
725 |
+
* ``os_release_file`` (string): The path name of the
|
726 |
+
`os-release file`_ that is actually used as a data source. The
|
727 |
+
empty string if no distro release file is used as a data source.
|
728 |
+
|
729 |
+
* ``distro_release_file`` (string): The path name of the
|
730 |
+
`distro release file`_ that is actually used as a data source. The
|
731 |
+
empty string if no distro release file is used as a data source.
|
732 |
+
|
733 |
+
* ``include_lsb`` (bool): The result of the ``include_lsb`` parameter.
|
734 |
+
This controls whether the lsb information will be loaded.
|
735 |
+
|
736 |
+
* ``include_uname`` (bool): The result of the ``include_uname``
|
737 |
+
parameter. This controls whether the uname information will
|
738 |
+
be loaded.
|
739 |
+
|
740 |
+
* ``include_oslevel`` (bool): The result of the ``include_oslevel``
|
741 |
+
parameter. This controls whether (AIX) oslevel information will be
|
742 |
+
loaded.
|
743 |
+
|
744 |
+
* ``root_dir`` (string): The result of the ``root_dir`` parameter.
|
745 |
+
The absolute path to the root directory to use to find distro-related
|
746 |
+
information files.
|
747 |
+
|
748 |
+
Raises:
|
749 |
+
|
750 |
+
* :py:exc:`ValueError`: Initialization parameters combination is not
|
751 |
+
supported.
|
752 |
+
|
753 |
+
* :py:exc:`OSError`: Some I/O issue with an os-release file or distro
|
754 |
+
release file.
|
755 |
+
|
756 |
+
* :py:exc:`UnicodeError`: A data source has unexpected characters or
|
757 |
+
uses an unexpected encoding.
|
758 |
+
"""
|
759 |
+
self.root_dir = root_dir
|
760 |
+
self.etc_dir = os.path.join(root_dir, "etc") if root_dir else _UNIXCONFDIR
|
761 |
+
self.usr_lib_dir = (
|
762 |
+
os.path.join(root_dir, "usr/lib") if root_dir else _UNIXUSRLIBDIR
|
763 |
+
)
|
764 |
+
|
765 |
+
if os_release_file:
|
766 |
+
self.os_release_file = os_release_file
|
767 |
+
else:
|
768 |
+
etc_dir_os_release_file = os.path.join(self.etc_dir, _OS_RELEASE_BASENAME)
|
769 |
+
usr_lib_os_release_file = os.path.join(
|
770 |
+
self.usr_lib_dir, _OS_RELEASE_BASENAME
|
771 |
+
)
|
772 |
+
|
773 |
+
# NOTE: The idea is to respect order **and** have it set
|
774 |
+
# at all times for API backwards compatibility.
|
775 |
+
if os.path.isfile(etc_dir_os_release_file) or not os.path.isfile(
|
776 |
+
usr_lib_os_release_file
|
777 |
+
):
|
778 |
+
self.os_release_file = etc_dir_os_release_file
|
779 |
+
else:
|
780 |
+
self.os_release_file = usr_lib_os_release_file
|
781 |
+
|
782 |
+
self.distro_release_file = distro_release_file or "" # updated later
|
783 |
+
|
784 |
+
is_root_dir_defined = root_dir is not None
|
785 |
+
if is_root_dir_defined and (include_lsb or include_uname or include_oslevel):
|
786 |
+
raise ValueError(
|
787 |
+
"Including subprocess data sources from specific root_dir is disallowed"
|
788 |
+
" to prevent false information"
|
789 |
+
)
|
790 |
+
self.include_lsb = (
|
791 |
+
include_lsb if include_lsb is not None else not is_root_dir_defined
|
792 |
+
)
|
793 |
+
self.include_uname = (
|
794 |
+
include_uname if include_uname is not None else not is_root_dir_defined
|
795 |
+
)
|
796 |
+
self.include_oslevel = (
|
797 |
+
include_oslevel if include_oslevel is not None else not is_root_dir_defined
|
798 |
+
)
|
799 |
+
|
800 |
+
def __repr__(self) -> str:
|
801 |
+
"""Return repr of all info"""
|
802 |
+
return (
|
803 |
+
"LinuxDistribution("
|
804 |
+
"os_release_file={self.os_release_file!r}, "
|
805 |
+
"distro_release_file={self.distro_release_file!r}, "
|
806 |
+
"include_lsb={self.include_lsb!r}, "
|
807 |
+
"include_uname={self.include_uname!r}, "
|
808 |
+
"include_oslevel={self.include_oslevel!r}, "
|
809 |
+
"root_dir={self.root_dir!r}, "
|
810 |
+
"_os_release_info={self._os_release_info!r}, "
|
811 |
+
"_lsb_release_info={self._lsb_release_info!r}, "
|
812 |
+
"_distro_release_info={self._distro_release_info!r}, "
|
813 |
+
"_uname_info={self._uname_info!r}, "
|
814 |
+
"_oslevel_info={self._oslevel_info!r})".format(self=self)
|
815 |
+
)
|
816 |
+
|
817 |
+
def linux_distribution(
|
818 |
+
self, full_distribution_name: bool = True
|
819 |
+
) -> Tuple[str, str, str]:
|
820 |
+
"""
|
821 |
+
Return information about the OS distribution that is compatible
|
822 |
+
with Python's :func:`platform.linux_distribution`, supporting a subset
|
823 |
+
of its parameters.
|
824 |
+
|
825 |
+
For details, see :func:`distro.linux_distribution`.
|
826 |
+
"""
|
827 |
+
return (
|
828 |
+
self.name() if full_distribution_name else self.id(),
|
829 |
+
self.version(),
|
830 |
+
self._os_release_info.get("release_codename") or self.codename(),
|
831 |
+
)
|
832 |
+
|
833 |
+
def id(self) -> str:
|
834 |
+
"""Return the distro ID of the OS distribution, as a string.
|
835 |
+
|
836 |
+
For details, see :func:`distro.id`.
|
837 |
+
"""
|
838 |
+
|
839 |
+
def normalize(distro_id: str, table: Dict[str, str]) -> str:
|
840 |
+
distro_id = distro_id.lower().replace(" ", "_")
|
841 |
+
return table.get(distro_id, distro_id)
|
842 |
+
|
843 |
+
distro_id = self.os_release_attr("id")
|
844 |
+
if distro_id:
|
845 |
+
return normalize(distro_id, NORMALIZED_OS_ID)
|
846 |
+
|
847 |
+
distro_id = self.lsb_release_attr("distributor_id")
|
848 |
+
if distro_id:
|
849 |
+
return normalize(distro_id, NORMALIZED_LSB_ID)
|
850 |
+
|
851 |
+
distro_id = self.distro_release_attr("id")
|
852 |
+
if distro_id:
|
853 |
+
return normalize(distro_id, NORMALIZED_DISTRO_ID)
|
854 |
+
|
855 |
+
distro_id = self.uname_attr("id")
|
856 |
+
if distro_id:
|
857 |
+
return normalize(distro_id, NORMALIZED_DISTRO_ID)
|
858 |
+
|
859 |
+
return ""
|
860 |
+
|
861 |
+
def name(self, pretty: bool = False) -> str:
|
862 |
+
"""
|
863 |
+
Return the name of the OS distribution, as a string.
|
864 |
+
|
865 |
+
For details, see :func:`distro.name`.
|
866 |
+
"""
|
867 |
+
name = (
|
868 |
+
self.os_release_attr("name")
|
869 |
+
or self.lsb_release_attr("distributor_id")
|
870 |
+
or self.distro_release_attr("name")
|
871 |
+
or self.uname_attr("name")
|
872 |
+
)
|
873 |
+
if pretty:
|
874 |
+
name = self.os_release_attr("pretty_name") or self.lsb_release_attr(
|
875 |
+
"description"
|
876 |
+
)
|
877 |
+
if not name:
|
878 |
+
name = self.distro_release_attr("name") or self.uname_attr("name")
|
879 |
+
version = self.version(pretty=True)
|
880 |
+
if version:
|
881 |
+
name = f"{name} {version}"
|
882 |
+
return name or ""
|
883 |
+
|
884 |
+
def version(self, pretty: bool = False, best: bool = False) -> str:
|
885 |
+
"""
|
886 |
+
Return the version of the OS distribution, as a string.
|
887 |
+
|
888 |
+
For details, see :func:`distro.version`.
|
889 |
+
"""
|
890 |
+
versions = [
|
891 |
+
self.os_release_attr("version_id"),
|
892 |
+
self.lsb_release_attr("release"),
|
893 |
+
self.distro_release_attr("version_id"),
|
894 |
+
self._parse_distro_release_content(self.os_release_attr("pretty_name")).get(
|
895 |
+
"version_id", ""
|
896 |
+
),
|
897 |
+
self._parse_distro_release_content(
|
898 |
+
self.lsb_release_attr("description")
|
899 |
+
).get("version_id", ""),
|
900 |
+
self.uname_attr("release"),
|
901 |
+
]
|
902 |
+
if self.uname_attr("id").startswith("aix"):
|
903 |
+
# On AIX platforms, prefer oslevel command output.
|
904 |
+
versions.insert(0, self.oslevel_info())
|
905 |
+
elif self.id() == "debian" or "debian" in self.like().split():
|
906 |
+
# On Debian-like, add debian_version file content to candidates list.
|
907 |
+
versions.append(self._debian_version)
|
908 |
+
version = ""
|
909 |
+
if best:
|
910 |
+
# This algorithm uses the last version in priority order that has
|
911 |
+
# the best precision. If the versions are not in conflict, that
|
912 |
+
# does not matter; otherwise, using the last one instead of the
|
913 |
+
# first one might be considered a surprise.
|
914 |
+
for v in versions:
|
915 |
+
if v.count(".") > version.count(".") or version == "":
|
916 |
+
version = v
|
917 |
+
else:
|
918 |
+
for v in versions:
|
919 |
+
if v != "":
|
920 |
+
version = v
|
921 |
+
break
|
922 |
+
if pretty and version and self.codename():
|
923 |
+
version = f"{version} ({self.codename()})"
|
924 |
+
return version
|
925 |
+
|
926 |
+
def version_parts(self, best: bool = False) -> Tuple[str, str, str]:
|
927 |
+
"""
|
928 |
+
Return the version of the OS distribution, as a tuple of version
|
929 |
+
numbers.
|
930 |
+
|
931 |
+
For details, see :func:`distro.version_parts`.
|
932 |
+
"""
|
933 |
+
version_str = self.version(best=best)
|
934 |
+
if version_str:
|
935 |
+
version_regex = re.compile(r"(\d+)\.?(\d+)?\.?(\d+)?")
|
936 |
+
matches = version_regex.match(version_str)
|
937 |
+
if matches:
|
938 |
+
major, minor, build_number = matches.groups()
|
939 |
+
return major, minor or "", build_number or ""
|
940 |
+
return "", "", ""
|
941 |
+
|
942 |
+
def major_version(self, best: bool = False) -> str:
|
943 |
+
"""
|
944 |
+
Return the major version number of the current distribution.
|
945 |
+
|
946 |
+
For details, see :func:`distro.major_version`.
|
947 |
+
"""
|
948 |
+
return self.version_parts(best)[0]
|
949 |
+
|
950 |
+
def minor_version(self, best: bool = False) -> str:
|
951 |
+
"""
|
952 |
+
Return the minor version number of the current distribution.
|
953 |
+
|
954 |
+
For details, see :func:`distro.minor_version`.
|
955 |
+
"""
|
956 |
+
return self.version_parts(best)[1]
|
957 |
+
|
958 |
+
def build_number(self, best: bool = False) -> str:
|
959 |
+
"""
|
960 |
+
Return the build number of the current distribution.
|
961 |
+
|
962 |
+
For details, see :func:`distro.build_number`.
|
963 |
+
"""
|
964 |
+
return self.version_parts(best)[2]
|
965 |
+
|
966 |
+
def like(self) -> str:
|
967 |
+
"""
|
968 |
+
Return the IDs of distributions that are like the OS distribution.
|
969 |
+
|
970 |
+
For details, see :func:`distro.like`.
|
971 |
+
"""
|
972 |
+
return self.os_release_attr("id_like") or ""
|
973 |
+
|
974 |
+
def codename(self) -> str:
|
975 |
+
"""
|
976 |
+
Return the codename of the OS distribution.
|
977 |
+
|
978 |
+
For details, see :func:`distro.codename`.
|
979 |
+
"""
|
980 |
+
try:
|
981 |
+
# Handle os_release specially since distros might purposefully set
|
982 |
+
# this to empty string to have no codename
|
983 |
+
return self._os_release_info["codename"]
|
984 |
+
except KeyError:
|
985 |
+
return (
|
986 |
+
self.lsb_release_attr("codename")
|
987 |
+
or self.distro_release_attr("codename")
|
988 |
+
or ""
|
989 |
+
)
|
990 |
+
|
991 |
+
def info(self, pretty: bool = False, best: bool = False) -> InfoDict:
|
992 |
+
"""
|
993 |
+
Return certain machine-readable information about the OS
|
994 |
+
distribution.
|
995 |
+
|
996 |
+
For details, see :func:`distro.info`.
|
997 |
+
"""
|
998 |
+
return InfoDict(
|
999 |
+
id=self.id(),
|
1000 |
+
version=self.version(pretty, best),
|
1001 |
+
version_parts=VersionDict(
|
1002 |
+
major=self.major_version(best),
|
1003 |
+
minor=self.minor_version(best),
|
1004 |
+
build_number=self.build_number(best),
|
1005 |
+
),
|
1006 |
+
like=self.like(),
|
1007 |
+
codename=self.codename(),
|
1008 |
+
)
|
1009 |
+
|
1010 |
+
def os_release_info(self) -> Dict[str, str]:
|
1011 |
+
"""
|
1012 |
+
Return a dictionary containing key-value pairs for the information
|
1013 |
+
items from the os-release file data source of the OS distribution.
|
1014 |
+
|
1015 |
+
For details, see :func:`distro.os_release_info`.
|
1016 |
+
"""
|
1017 |
+
return self._os_release_info
|
1018 |
+
|
1019 |
+
def lsb_release_info(self) -> Dict[str, str]:
|
1020 |
+
"""
|
1021 |
+
Return a dictionary containing key-value pairs for the information
|
1022 |
+
items from the lsb_release command data source of the OS
|
1023 |
+
distribution.
|
1024 |
+
|
1025 |
+
For details, see :func:`distro.lsb_release_info`.
|
1026 |
+
"""
|
1027 |
+
return self._lsb_release_info
|
1028 |
+
|
1029 |
+
def distro_release_info(self) -> Dict[str, str]:
|
1030 |
+
"""
|
1031 |
+
Return a dictionary containing key-value pairs for the information
|
1032 |
+
items from the distro release file data source of the OS
|
1033 |
+
distribution.
|
1034 |
+
|
1035 |
+
For details, see :func:`distro.distro_release_info`.
|
1036 |
+
"""
|
1037 |
+
return self._distro_release_info
|
1038 |
+
|
1039 |
+
def uname_info(self) -> Dict[str, str]:
|
1040 |
+
"""
|
1041 |
+
Return a dictionary containing key-value pairs for the information
|
1042 |
+
items from the uname command data source of the OS distribution.
|
1043 |
+
|
1044 |
+
For details, see :func:`distro.uname_info`.
|
1045 |
+
"""
|
1046 |
+
return self._uname_info
|
1047 |
+
|
1048 |
+
def oslevel_info(self) -> str:
|
1049 |
+
"""
|
1050 |
+
Return AIX' oslevel command output.
|
1051 |
+
"""
|
1052 |
+
return self._oslevel_info
|
1053 |
+
|
1054 |
+
def os_release_attr(self, attribute: str) -> str:
|
1055 |
+
"""
|
1056 |
+
Return a single named information item from the os-release file data
|
1057 |
+
source of the OS distribution.
|
1058 |
+
|
1059 |
+
For details, see :func:`distro.os_release_attr`.
|
1060 |
+
"""
|
1061 |
+
return self._os_release_info.get(attribute, "")
|
1062 |
+
|
1063 |
+
def lsb_release_attr(self, attribute: str) -> str:
|
1064 |
+
"""
|
1065 |
+
Return a single named information item from the lsb_release command
|
1066 |
+
output data source of the OS distribution.
|
1067 |
+
|
1068 |
+
For details, see :func:`distro.lsb_release_attr`.
|
1069 |
+
"""
|
1070 |
+
return self._lsb_release_info.get(attribute, "")
|
1071 |
+
|
1072 |
+
def distro_release_attr(self, attribute: str) -> str:
|
1073 |
+
"""
|
1074 |
+
Return a single named information item from the distro release file
|
1075 |
+
data source of the OS distribution.
|
1076 |
+
|
1077 |
+
For details, see :func:`distro.distro_release_attr`.
|
1078 |
+
"""
|
1079 |
+
return self._distro_release_info.get(attribute, "")
|
1080 |
+
|
1081 |
+
def uname_attr(self, attribute: str) -> str:
|
1082 |
+
"""
|
1083 |
+
Return a single named information item from the uname command
|
1084 |
+
output data source of the OS distribution.
|
1085 |
+
|
1086 |
+
For details, see :func:`distro.uname_attr`.
|
1087 |
+
"""
|
1088 |
+
return self._uname_info.get(attribute, "")
|
1089 |
+
|
1090 |
+
@cached_property
|
1091 |
+
def _os_release_info(self) -> Dict[str, str]:
|
1092 |
+
"""
|
1093 |
+
Get the information items from the specified os-release file.
|
1094 |
+
|
1095 |
+
Returns:
|
1096 |
+
A dictionary containing all information items.
|
1097 |
+
"""
|
1098 |
+
if os.path.isfile(self.os_release_file):
|
1099 |
+
with open(self.os_release_file, encoding="utf-8") as release_file:
|
1100 |
+
return self._parse_os_release_content(release_file)
|
1101 |
+
return {}
|
1102 |
+
|
1103 |
+
@staticmethod
|
1104 |
+
def _parse_os_release_content(lines: TextIO) -> Dict[str, str]:
|
1105 |
+
"""
|
1106 |
+
Parse the lines of an os-release file.
|
1107 |
+
|
1108 |
+
Parameters:
|
1109 |
+
|
1110 |
+
* lines: Iterable through the lines in the os-release file.
|
1111 |
+
Each line must be a unicode string or a UTF-8 encoded byte
|
1112 |
+
string.
|
1113 |
+
|
1114 |
+
Returns:
|
1115 |
+
A dictionary containing all information items.
|
1116 |
+
"""
|
1117 |
+
props = {}
|
1118 |
+
lexer = shlex.shlex(lines, posix=True)
|
1119 |
+
lexer.whitespace_split = True
|
1120 |
+
|
1121 |
+
tokens = list(lexer)
|
1122 |
+
for token in tokens:
|
1123 |
+
# At this point, all shell-like parsing has been done (i.e.
|
1124 |
+
# comments processed, quotes and backslash escape sequences
|
1125 |
+
# processed, multi-line values assembled, trailing newlines
|
1126 |
+
# stripped, etc.), so the tokens are now either:
|
1127 |
+
# * variable assignments: var=value
|
1128 |
+
# * commands or their arguments (not allowed in os-release)
|
1129 |
+
# Ignore any tokens that are not variable assignments
|
1130 |
+
if "=" in token:
|
1131 |
+
k, v = token.split("=", 1)
|
1132 |
+
props[k.lower()] = v
|
1133 |
+
|
1134 |
+
if "version" in props:
|
1135 |
+
# extract release codename (if any) from version attribute
|
1136 |
+
match = re.search(r"\((\D+)\)|,\s*(\D+)", props["version"])
|
1137 |
+
if match:
|
1138 |
+
release_codename = match.group(1) or match.group(2)
|
1139 |
+
props["codename"] = props["release_codename"] = release_codename
|
1140 |
+
|
1141 |
+
if "version_codename" in props:
|
1142 |
+
# os-release added a version_codename field. Use that in
|
1143 |
+
# preference to anything else Note that some distros purposefully
|
1144 |
+
# do not have code names. They should be setting
|
1145 |
+
# version_codename=""
|
1146 |
+
props["codename"] = props["version_codename"]
|
1147 |
+
elif "ubuntu_codename" in props:
|
1148 |
+
# Same as above but a non-standard field name used on older Ubuntus
|
1149 |
+
props["codename"] = props["ubuntu_codename"]
|
1150 |
+
|
1151 |
+
return props
|
1152 |
+
|
1153 |
+
@cached_property
|
1154 |
+
def _lsb_release_info(self) -> Dict[str, str]:
|
1155 |
+
"""
|
1156 |
+
Get the information items from the lsb_release command output.
|
1157 |
+
|
1158 |
+
Returns:
|
1159 |
+
A dictionary containing all information items.
|
1160 |
+
"""
|
1161 |
+
if not self.include_lsb:
|
1162 |
+
return {}
|
1163 |
+
try:
|
1164 |
+
cmd = ("lsb_release", "-a")
|
1165 |
+
stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
|
1166 |
+
# Command not found or lsb_release returned error
|
1167 |
+
except (OSError, subprocess.CalledProcessError):
|
1168 |
+
return {}
|
1169 |
+
content = self._to_str(stdout).splitlines()
|
1170 |
+
return self._parse_lsb_release_content(content)
|
1171 |
+
|
1172 |
+
@staticmethod
|
1173 |
+
def _parse_lsb_release_content(lines: Iterable[str]) -> Dict[str, str]:
|
1174 |
+
"""
|
1175 |
+
Parse the output of the lsb_release command.
|
1176 |
+
|
1177 |
+
Parameters:
|
1178 |
+
|
1179 |
+
* lines: Iterable through the lines of the lsb_release output.
|
1180 |
+
Each line must be a unicode string or a UTF-8 encoded byte
|
1181 |
+
string.
|
1182 |
+
|
1183 |
+
Returns:
|
1184 |
+
A dictionary containing all information items.
|
1185 |
+
"""
|
1186 |
+
props = {}
|
1187 |
+
for line in lines:
|
1188 |
+
kv = line.strip("\n").split(":", 1)
|
1189 |
+
if len(kv) != 2:
|
1190 |
+
# Ignore lines without colon.
|
1191 |
+
continue
|
1192 |
+
k, v = kv
|
1193 |
+
props.update({k.replace(" ", "_").lower(): v.strip()})
|
1194 |
+
return props
|
1195 |
+
|
1196 |
+
@cached_property
|
1197 |
+
def _uname_info(self) -> Dict[str, str]:
|
1198 |
+
if not self.include_uname:
|
1199 |
+
return {}
|
1200 |
+
try:
|
1201 |
+
cmd = ("uname", "-rs")
|
1202 |
+
stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
|
1203 |
+
except OSError:
|
1204 |
+
return {}
|
1205 |
+
content = self._to_str(stdout).splitlines()
|
1206 |
+
return self._parse_uname_content(content)
|
1207 |
+
|
1208 |
+
@cached_property
|
1209 |
+
def _oslevel_info(self) -> str:
|
1210 |
+
if not self.include_oslevel:
|
1211 |
+
return ""
|
1212 |
+
try:
|
1213 |
+
stdout = subprocess.check_output("oslevel", stderr=subprocess.DEVNULL)
|
1214 |
+
except (OSError, subprocess.CalledProcessError):
|
1215 |
+
return ""
|
1216 |
+
return self._to_str(stdout).strip()
|
1217 |
+
|
1218 |
+
@cached_property
|
1219 |
+
def _debian_version(self) -> str:
|
1220 |
+
try:
|
1221 |
+
with open(
|
1222 |
+
os.path.join(self.etc_dir, "debian_version"), encoding="ascii"
|
1223 |
+
) as fp:
|
1224 |
+
return fp.readline().rstrip()
|
1225 |
+
except FileNotFoundError:
|
1226 |
+
return ""
|
1227 |
+
|
1228 |
+
@staticmethod
|
1229 |
+
def _parse_uname_content(lines: Sequence[str]) -> Dict[str, str]:
|
1230 |
+
if not lines:
|
1231 |
+
return {}
|
1232 |
+
props = {}
|
1233 |
+
match = re.search(r"^([^\s]+)\s+([\d\.]+)", lines[0].strip())
|
1234 |
+
if match:
|
1235 |
+
name, version = match.groups()
|
1236 |
+
|
1237 |
+
# This is to prevent the Linux kernel version from
|
1238 |
+
# appearing as the 'best' version on otherwise
|
1239 |
+
# identifiable distributions.
|
1240 |
+
if name == "Linux":
|
1241 |
+
return {}
|
1242 |
+
props["id"] = name.lower()
|
1243 |
+
props["name"] = name
|
1244 |
+
props["release"] = version
|
1245 |
+
return props
|
1246 |
+
|
1247 |
+
@staticmethod
|
1248 |
+
def _to_str(bytestring: bytes) -> str:
|
1249 |
+
encoding = sys.getfilesystemencoding()
|
1250 |
+
return bytestring.decode(encoding)
|
1251 |
+
|
1252 |
+
@cached_property
|
1253 |
+
def _distro_release_info(self) -> Dict[str, str]:
|
1254 |
+
"""
|
1255 |
+
Get the information items from the specified distro release file.
|
1256 |
+
|
1257 |
+
Returns:
|
1258 |
+
A dictionary containing all information items.
|
1259 |
+
"""
|
1260 |
+
if self.distro_release_file:
|
1261 |
+
# If it was specified, we use it and parse what we can, even if
|
1262 |
+
# its file name or content does not match the expected pattern.
|
1263 |
+
distro_info = self._parse_distro_release_file(self.distro_release_file)
|
1264 |
+
basename = os.path.basename(self.distro_release_file)
|
1265 |
+
# The file name pattern for user-specified distro release files
|
1266 |
+
# is somewhat more tolerant (compared to when searching for the
|
1267 |
+
# file), because we want to use what was specified as best as
|
1268 |
+
# possible.
|
1269 |
+
match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename)
|
1270 |
+
else:
|
1271 |
+
try:
|
1272 |
+
basenames = [
|
1273 |
+
basename
|
1274 |
+
for basename in os.listdir(self.etc_dir)
|
1275 |
+
if basename not in _DISTRO_RELEASE_IGNORE_BASENAMES
|
1276 |
+
and os.path.isfile(os.path.join(self.etc_dir, basename))
|
1277 |
+
]
|
1278 |
+
# We sort for repeatability in cases where there are multiple
|
1279 |
+
# distro specific files; e.g. CentOS, Oracle, Enterprise all
|
1280 |
+
# containing `redhat-release` on top of their own.
|
1281 |
+
basenames.sort()
|
1282 |
+
except OSError:
|
1283 |
+
# This may occur when /etc is not readable but we can't be
|
1284 |
+
# sure about the *-release files. Check common entries of
|
1285 |
+
# /etc for information. If they turn out to not be there the
|
1286 |
+
# error is handled in `_parse_distro_release_file()`.
|
1287 |
+
basenames = _DISTRO_RELEASE_BASENAMES
|
1288 |
+
for basename in basenames:
|
1289 |
+
match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename)
|
1290 |
+
if match is None:
|
1291 |
+
continue
|
1292 |
+
filepath = os.path.join(self.etc_dir, basename)
|
1293 |
+
distro_info = self._parse_distro_release_file(filepath)
|
1294 |
+
# The name is always present if the pattern matches.
|
1295 |
+
if "name" not in distro_info:
|
1296 |
+
continue
|
1297 |
+
self.distro_release_file = filepath
|
1298 |
+
break
|
1299 |
+
else: # the loop didn't "break": no candidate.
|
1300 |
+
return {}
|
1301 |
+
|
1302 |
+
if match is not None:
|
1303 |
+
distro_info["id"] = match.group(1)
|
1304 |
+
|
1305 |
+
# CloudLinux < 7: manually enrich info with proper id.
|
1306 |
+
if "cloudlinux" in distro_info.get("name", "").lower():
|
1307 |
+
distro_info["id"] = "cloudlinux"
|
1308 |
+
|
1309 |
+
return distro_info
|
1310 |
+
|
1311 |
+
def _parse_distro_release_file(self, filepath: str) -> Dict[str, str]:
|
1312 |
+
"""
|
1313 |
+
Parse a distro release file.
|
1314 |
+
|
1315 |
+
Parameters:
|
1316 |
+
|
1317 |
+
* filepath: Path name of the distro release file.
|
1318 |
+
|
1319 |
+
Returns:
|
1320 |
+
A dictionary containing all information items.
|
1321 |
+
"""
|
1322 |
+
try:
|
1323 |
+
with open(filepath, encoding="utf-8") as fp:
|
1324 |
+
# Only parse the first line. For instance, on SLES there
|
1325 |
+
# are multiple lines. We don't want them...
|
1326 |
+
return self._parse_distro_release_content(fp.readline())
|
1327 |
+
except OSError:
|
1328 |
+
# Ignore not being able to read a specific, seemingly version
|
1329 |
+
# related file.
|
1330 |
+
# See https://github.com/python-distro/distro/issues/162
|
1331 |
+
return {}
|
1332 |
+
|
1333 |
+
@staticmethod
|
1334 |
+
def _parse_distro_release_content(line: str) -> Dict[str, str]:
|
1335 |
+
"""
|
1336 |
+
Parse a line from a distro release file.
|
1337 |
+
|
1338 |
+
Parameters:
|
1339 |
+
* line: Line from the distro release file. Must be a unicode string
|
1340 |
+
or a UTF-8 encoded byte string.
|
1341 |
+
|
1342 |
+
Returns:
|
1343 |
+
A dictionary containing all information items.
|
1344 |
+
"""
|
1345 |
+
matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match(line.strip()[::-1])
|
1346 |
+
distro_info = {}
|
1347 |
+
if matches:
|
1348 |
+
# regexp ensures non-None
|
1349 |
+
distro_info["name"] = matches.group(3)[::-1]
|
1350 |
+
if matches.group(2):
|
1351 |
+
distro_info["version_id"] = matches.group(2)[::-1]
|
1352 |
+
if matches.group(1):
|
1353 |
+
distro_info["codename"] = matches.group(1)[::-1]
|
1354 |
+
elif line:
|
1355 |
+
distro_info["name"] = line.strip()
|
1356 |
+
return distro_info
|
1357 |
+
|
1358 |
+
|
1359 |
+
_distro = LinuxDistribution()
|
1360 |
+
|
1361 |
+
|
1362 |
+
def main() -> None:
|
1363 |
+
logger = logging.getLogger(__name__)
|
1364 |
+
logger.setLevel(logging.DEBUG)
|
1365 |
+
logger.addHandler(logging.StreamHandler(sys.stdout))
|
1366 |
+
|
1367 |
+
parser = argparse.ArgumentParser(description="OS distro info tool")
|
1368 |
+
parser.add_argument(
|
1369 |
+
"--json", "-j", help="Output in machine readable format", action="store_true"
|
1370 |
+
)
|
1371 |
+
|
1372 |
+
parser.add_argument(
|
1373 |
+
"--root-dir",
|
1374 |
+
"-r",
|
1375 |
+
type=str,
|
1376 |
+
dest="root_dir",
|
1377 |
+
help="Path to the root filesystem directory (defaults to /)",
|
1378 |
+
)
|
1379 |
+
|
1380 |
+
args = parser.parse_args()
|
1381 |
+
|
1382 |
+
if args.root_dir:
|
1383 |
+
dist = LinuxDistribution(
|
1384 |
+
include_lsb=False,
|
1385 |
+
include_uname=False,
|
1386 |
+
include_oslevel=False,
|
1387 |
+
root_dir=args.root_dir,
|
1388 |
+
)
|
1389 |
+
else:
|
1390 |
+
dist = _distro
|
1391 |
+
|
1392 |
+
if args.json:
|
1393 |
+
logger.info(json.dumps(dist.info(), indent=4, sort_keys=True))
|
1394 |
+
else:
|
1395 |
+
logger.info("Name: %s", dist.name(pretty=True))
|
1396 |
+
distribution_version = dist.version(pretty=True)
|
1397 |
+
logger.info("Version: %s", distribution_version)
|
1398 |
+
distribution_codename = dist.codename()
|
1399 |
+
logger.info("Codename: %s", distribution_codename)
|
1400 |
+
|
1401 |
+
|
1402 |
+
if __name__ == "__main__":
|
1403 |
+
main()
|
.venv/lib/python3.11/site-packages/distro/py.typed
ADDED
File without changes
|
.venv/lib/python3.11/site-packages/gguf-0.10.0.dist-info/INSTALLER
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
pip
|
.venv/lib/python3.11/site-packages/gguf-0.10.0.dist-info/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2023 Georgi Gerganov
|
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.11/site-packages/gguf-0.10.0.dist-info/METADATA
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Metadata-Version: 2.1
|
2 |
+
Name: gguf
|
3 |
+
Version: 0.10.0
|
4 |
+
Summary: Read and write ML models in GGUF for GGML
|
5 |
+
Home-page: https://ggml.ai
|
6 |
+
Keywords: ggml,gguf,llama.cpp
|
7 |
+
Author: GGML
|
8 |
+
Author-email: [email protected]
|
9 |
+
Requires-Python: >=3.8
|
10 |
+
Classifier: License :: OSI Approved :: MIT License
|
11 |
+
Classifier: Operating System :: OS Independent
|
12 |
+
Classifier: Programming Language :: Python :: 3
|
13 |
+
Classifier: Programming Language :: Python :: 3.8
|
14 |
+
Classifier: Programming Language :: Python :: 3.9
|
15 |
+
Classifier: Programming Language :: Python :: 3.10
|
16 |
+
Classifier: Programming Language :: Python :: 3.11
|
17 |
+
Classifier: Programming Language :: Python :: 3.12
|
18 |
+
Requires-Dist: numpy (>=1.17)
|
19 |
+
Requires-Dist: pyyaml (>=5.1)
|
20 |
+
Requires-Dist: tqdm (>=4.27)
|
21 |
+
Project-URL: Repository, https://github.com/ggerganov/llama.cpp
|
22 |
+
Description-Content-Type: text/markdown
|
23 |
+
|
24 |
+
## gguf
|
25 |
+
|
26 |
+
This is a Python package for writing binary files in the [GGUF](https://github.com/ggerganov/ggml/pull/302)
|
27 |
+
(GGML Universal File) format.
|
28 |
+
|
29 |
+
See [convert_hf_to_gguf.py](https://github.com/ggerganov/llama.cpp/blob/master/convert_hf_to_gguf.py)
|
30 |
+
as an example for its usage.
|
31 |
+
|
32 |
+
## Installation
|
33 |
+
```sh
|
34 |
+
pip install gguf
|
35 |
+
```
|
36 |
+
|
37 |
+
## API Examples/Simple Tools
|
38 |
+
|
39 |
+
[examples/writer.py](https://github.com/ggerganov/llama.cpp/blob/master/gguf-py/examples/writer.py) — Generates `example.gguf` in the current directory to demonstrate generating a GGUF file. Note that this file cannot be used as a model.
|
40 |
+
|
41 |
+
[scripts/gguf_dump.py](https://github.com/ggerganov/llama.cpp/blob/master/gguf-py/scripts/gguf_dump.py) — Dumps a GGUF file's metadata to the console.
|
42 |
+
|
43 |
+
[scripts/gguf_set_metadata.py](https://github.com/ggerganov/llama.cpp/blob/master/gguf-py/scripts/gguf_set_metadata.py) — Allows changing simple metadata values in a GGUF file by key.
|
44 |
+
|
45 |
+
[scripts/gguf_convert_endian.py](https://github.com/ggerganov/llama.cpp/blob/master/gguf-py/scripts/gguf_convert_endian.py) — Allows converting the endianness of GGUF files.
|
46 |
+
|
47 |
+
[scripts/gguf_new_metadata.py](https://github.com/ggerganov/llama.cpp/blob/master/gguf-py/scripts/gguf_new_metadata.py) — Copies a GGUF file with added/modified/removed metadata values.
|
48 |
+
|
49 |
+
## Development
|
50 |
+
Maintainers who participate in development of this package are advised to install it in editable mode:
|
51 |
+
|
52 |
+
```sh
|
53 |
+
cd /path/to/llama.cpp/gguf-py
|
54 |
+
|
55 |
+
pip install --editable .
|
56 |
+
```
|
57 |
+
|
58 |
+
**Note**: This may require to upgrade your Pip installation, with a message saying that editable installation currently requires `setup.py`.
|
59 |
+
In this case, upgrade Pip to the latest:
|
60 |
+
|
61 |
+
```sh
|
62 |
+
pip install --upgrade pip
|
63 |
+
```
|
64 |
+
|
65 |
+
## Automatic publishing with CI
|
66 |
+
|
67 |
+
There's a GitHub workflow to make a release automatically upon creation of tags in a specified format.
|
68 |
+
|
69 |
+
1. Bump the version in `pyproject.toml`.
|
70 |
+
2. Create a tag named `gguf-vx.x.x` where `x.x.x` is the semantic version number.
|
71 |
+
|
72 |
+
```sh
|
73 |
+
git tag -a gguf-v1.0.0 -m "Version 1.0 release"
|
74 |
+
```
|
75 |
+
|
76 |
+
3. Push the tags.
|
77 |
+
|
78 |
+
```sh
|
79 |
+
git push origin --tags
|
80 |
+
```
|
81 |
+
|
82 |
+
## Manual publishing
|
83 |
+
If you want to publish the package manually for any reason, you need to have `twine` and `build` installed:
|
84 |
+
|
85 |
+
```sh
|
86 |
+
pip install build twine
|
87 |
+
```
|
88 |
+
|
89 |
+
Then, follow these steps to release a new version:
|
90 |
+
|
91 |
+
1. Bump the version in `pyproject.toml`.
|
92 |
+
2. Build the package:
|
93 |
+
|
94 |
+
```sh
|
95 |
+
python -m build
|
96 |
+
```
|
97 |
+
|
98 |
+
3. Upload the generated distribution archives:
|
99 |
+
|
100 |
+
```sh
|
101 |
+
python -m twine upload dist/*
|
102 |
+
```
|
103 |
+
|
104 |
+
## Run Unit Tests
|
105 |
+
|
106 |
+
From root of this repository you can run this command to run all the unit tests
|
107 |
+
|
108 |
+
```bash
|
109 |
+
python -m unittest discover ./gguf-py -v
|
110 |
+
```
|
111 |
+
|
112 |
+
## TODO
|
113 |
+
- [ ] Include conversion scripts as command line entry points in this package.
|
114 |
+
|
.venv/lib/python3.11/site-packages/gguf-0.10.0.dist-info/RECORD
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
../../../bin/gguf-convert-endian,sha256=W53Q9wLM4ktx91uKrLfyuFNGS7UCbZr-mA2U66A_W0E,276
|
2 |
+
../../../bin/gguf-dump,sha256=v29_dyj4DF8zullVHEvLoQotNn0dgtrt8f-NjwDigFw,256
|
3 |
+
../../../bin/gguf-new-metadata,sha256=UwjDwictRuL-TFKI2mlnkzB8YzGJSNWJ69870J9w64Y,272
|
4 |
+
../../../bin/gguf-set-metadata,sha256=iqt1mYpW1z41SzKpVu0r6NLBVYPDc-k06JH7cmo-e9s,272
|
5 |
+
gguf-0.10.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
6 |
+
gguf-0.10.0.dist-info/LICENSE,sha256=73jH5mWeNMeYGU8NNE6AfHIt5wy8oTWe9UdyZh4Ryjg,1072
|
7 |
+
gguf-0.10.0.dist-info/METADATA,sha256=0jck7V9EOoT24ugiLaorfqFzhmN3eJM7lj-fyq8tvy8,3533
|
8 |
+
gguf-0.10.0.dist-info/RECORD,,
|
9 |
+
gguf-0.10.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
10 |
+
gguf-0.10.0.dist-info/entry_points.txt,sha256=6SBOHW2PZstAG6hvoQ63pyxPF8CIGjGLXZyG-NFFnAc,227
|
11 |
+
gguf/__init__.py,sha256=PM_AEEzX6ojGAodDt78_LIm19HRCXeA6IXpgcjINfC8,219
|
12 |
+
gguf/__pycache__/__init__.cpython-311.pyc,,
|
13 |
+
gguf/__pycache__/constants.cpython-311.pyc,,
|
14 |
+
gguf/__pycache__/gguf.cpython-311.pyc,,
|
15 |
+
gguf/__pycache__/gguf_reader.cpython-311.pyc,,
|
16 |
+
gguf/__pycache__/gguf_writer.cpython-311.pyc,,
|
17 |
+
gguf/__pycache__/lazy.cpython-311.pyc,,
|
18 |
+
gguf/__pycache__/metadata.cpython-311.pyc,,
|
19 |
+
gguf/__pycache__/quants.cpython-311.pyc,,
|
20 |
+
gguf/__pycache__/tensor_mapping.cpython-311.pyc,,
|
21 |
+
gguf/__pycache__/utility.cpython-311.pyc,,
|
22 |
+
gguf/__pycache__/vocab.cpython-311.pyc,,
|
23 |
+
gguf/constants.py,sha256=00pCXTqoWP36ZR9OcuxJfhezZfxqjUTKGCNvGMrkLGU,49158
|
24 |
+
gguf/gguf.py,sha256=8MDu7a0JEXhLUv_tjhYqDrWubVNc41cFvBYZbkZZenI,478
|
25 |
+
gguf/gguf_reader.py,sha256=0Y86qmxYfPNq3u_AiAwSnhU_G-V2SjXK2b7CM3MoPP4,12365
|
26 |
+
gguf/gguf_writer.py,sha256=ZWW_XwN6tyDIzBCwl6ARDwwRZ9TewNMV32IQaVYRNP8,35090
|
27 |
+
gguf/lazy.py,sha256=QwxFAtj-5nIm_a3mvLBezpShFuo-pjJhoAiXreK9ITQ,8601
|
28 |
+
gguf/metadata.py,sha256=nFEqgODwH6jYF3_jcycZkN4FjLnfXOQ7A73cLKZJb0Y,25722
|
29 |
+
gguf/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30 |
+
gguf/quants.py,sha256=_6kmSprMfawH3gcPz9WbxnlXCeZQIYivf_HjfUvUkM0,57336
|
31 |
+
gguf/tensor_mapping.py,sha256=8CpqXKwKYFz6v11Fpzhe85hPcH18gnieh_FQsISpcVc,30893
|
32 |
+
gguf/utility.py,sha256=jbd1bduLFjjNAQhjghSyrRQfJ_kjiTFhRAZxm0oabZw,2934
|
33 |
+
gguf/vocab.py,sha256=N4PNulV8x_m7cdbmbUBF3nqQ0UXGTDi31oEIh3h8hAs,19046
|
34 |
+
scripts/__init__.py,sha256=-Az7fR5lhVb9GPB5U_BaDb8Xp706km53vSY7aXQYw9I,297
|
35 |
+
scripts/__pycache__/__init__.cpython-311.pyc,,
|
36 |
+
scripts/__pycache__/gguf_convert_endian.cpython-311.pyc,,
|
37 |
+
scripts/__pycache__/gguf_dump.cpython-311.pyc,,
|
38 |
+
scripts/__pycache__/gguf_hash.cpython-311.pyc,,
|
39 |
+
scripts/__pycache__/gguf_new_metadata.cpython-311.pyc,,
|
40 |
+
scripts/__pycache__/gguf_set_metadata.cpython-311.pyc,,
|
41 |
+
scripts/gguf_convert_endian.py,sha256=tcpe1O6xLTSetYD5T8dYcDN7cwiTWS-5sH7iFCP7ga8,5279
|
42 |
+
scripts/gguf_dump.py,sha256=Ej3XWrYupFOg-Bz-ff9EAN5hdmp2OCdEkd46D4PtZ58,21934
|
43 |
+
scripts/gguf_hash.py,sha256=DtzQ3xSdS8bHxdsp8ELQaBlaZiqqDBXzqtRSEzYTkhM,3711
|
44 |
+
scripts/gguf_new_metadata.py,sha256=bGuF8iXkElxIsr4mR952DHEBTosA9ob-UkF-zEqlPqo,10713
|
45 |
+
scripts/gguf_set_metadata.py,sha256=9jISgnh2atbwKh-68oN5b0wLxs0mYpXOWILjuqLTt-Q,4131
|
.venv/lib/python3.11/site-packages/gguf-0.10.0.dist-info/WHEEL
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Wheel-Version: 1.0
|
2 |
+
Generator: poetry-core 1.9.0
|
3 |
+
Root-Is-Purelib: true
|
4 |
+
Tag: py3-none-any
|
.venv/lib/python3.11/site-packages/gguf-0.10.0.dist-info/entry_points.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[console_scripts]
|
2 |
+
gguf-convert-endian=scripts:gguf_convert_endian_entrypoint
|
3 |
+
gguf-dump=scripts:gguf_dump_entrypoint
|
4 |
+
gguf-new-metadata=scripts:gguf_new_metadata_entrypoint
|
5 |
+
gguf-set-metadata=scripts:gguf_set_metadata_entrypoint
|
6 |
+
|
.venv/lib/python3.11/site-packages/mistral_common/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
__version__ = "1.5.2"
|
.venv/lib/python3.11/site-packages/mistral_common/base.py
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel, ConfigDict
|
2 |
+
|
3 |
+
|
4 |
+
class MistralBase(BaseModel):
|
5 |
+
"""
|
6 |
+
Base class for all Mistral Pydantic models.
|
7 |
+
"""
|
8 |
+
|
9 |
+
model_config = ConfigDict(extra="forbid", validate_default=True, use_enum_values=True)
|
.venv/lib/python3.11/site-packages/mistral_common/exceptions.py
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Optional
|
2 |
+
|
3 |
+
|
4 |
+
class MistralCommonException(Exception):
|
5 |
+
message: str = "Internal server error"
|
6 |
+
|
7 |
+
def __init__(
|
8 |
+
self,
|
9 |
+
message: Optional[str] = None,
|
10 |
+
) -> None:
|
11 |
+
if message:
|
12 |
+
self.message = message
|
13 |
+
|
14 |
+
|
15 |
+
class TokenizerException(MistralCommonException):
|
16 |
+
def __init__(self, message: str) -> None:
|
17 |
+
super().__init__(message)
|
18 |
+
|
19 |
+
|
20 |
+
class UnsupportedTokenizerFeatureException(MistralCommonException):
|
21 |
+
def __init__(self, message: str) -> None:
|
22 |
+
super().__init__(message)
|
23 |
+
|
24 |
+
|
25 |
+
class InvalidRequestException(MistralCommonException):
|
26 |
+
def __init__(self, message: str) -> None:
|
27 |
+
super().__init__(message)
|
28 |
+
|
29 |
+
|
30 |
+
class InvalidSystemPromptException(MistralCommonException):
|
31 |
+
def __init__(self, message: str) -> None:
|
32 |
+
super().__init__(message)
|
33 |
+
|
34 |
+
|
35 |
+
class InvalidMessageStructureException(MistralCommonException):
|
36 |
+
def __init__(self, message: str) -> None:
|
37 |
+
super().__init__(message)
|
38 |
+
|
39 |
+
|
40 |
+
class InvalidAssistantMessageException(MistralCommonException):
|
41 |
+
def __init__(self, message: str) -> None:
|
42 |
+
super().__init__(message)
|
43 |
+
|
44 |
+
|
45 |
+
class InvalidToolMessageException(MistralCommonException):
|
46 |
+
def __init__(self, message: str) -> None:
|
47 |
+
super().__init__(message)
|
48 |
+
|
49 |
+
|
50 |
+
class InvalidToolSchemaException(MistralCommonException):
|
51 |
+
def __init__(self, message: str) -> None:
|
52 |
+
super().__init__(message)
|
53 |
+
|
54 |
+
|
55 |
+
class InvalidUserMessageException(MistralCommonException):
|
56 |
+
def __init__(self, message: str) -> None:
|
57 |
+
super().__init__(message)
|
58 |
+
|
59 |
+
|
60 |
+
class InvalidFunctionCallException(MistralCommonException):
|
61 |
+
def __init__(self, message: str) -> None:
|
62 |
+
super().__init__(message)
|
63 |
+
|
64 |
+
|
65 |
+
class InvalidToolException(MistralCommonException):
|
66 |
+
def __init__(self, message: str) -> None:
|
67 |
+
super().__init__(message)
|
.venv/lib/python3.11/site-packages/mistral_common/multimodal.py
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import base64
|
2 |
+
import io
|
3 |
+
from typing import Union
|
4 |
+
|
5 |
+
import requests
|
6 |
+
from PIL import Image
|
7 |
+
from pydantic import BeforeValidator, PlainSerializer, SerializationInfo
|
8 |
+
from typing_extensions import Annotated
|
9 |
+
|
10 |
+
from mistral_common import __version__
|
11 |
+
|
12 |
+
|
13 |
+
def download_image(url: str) -> Image.Image:
|
14 |
+
headers = {"User-Agent": f"mistral-common/{__version__}"}
|
15 |
+
try:
|
16 |
+
# Make a request to download the image
|
17 |
+
response = requests.get(url, headers=headers)
|
18 |
+
response.raise_for_status() # Raise an error for bad responses (4xx, 5xx)
|
19 |
+
|
20 |
+
# Convert the image content to a PIL Image
|
21 |
+
img = Image.open(io.BytesIO(response.content))
|
22 |
+
return img
|
23 |
+
|
24 |
+
except requests.exceptions.RequestException as e:
|
25 |
+
raise RuntimeError(f"Error downloading the image from {url}: {e}.")
|
26 |
+
except Exception as e:
|
27 |
+
raise RuntimeError(f"Error converting to PIL image: {e}")
|
28 |
+
|
29 |
+
|
30 |
+
def maybe_load_image_from_str_or_bytes(x: Union[Image.Image, str, bytes]) -> Image.Image:
|
31 |
+
if isinstance(x, Image.Image):
|
32 |
+
return x
|
33 |
+
if isinstance(x, bytes):
|
34 |
+
try:
|
35 |
+
return Image.open(io.BytesIO(x))
|
36 |
+
except Exception:
|
37 |
+
raise RuntimeError("Encountered an error when loading image from bytes.")
|
38 |
+
|
39 |
+
try:
|
40 |
+
image = Image.open(io.BytesIO(base64.b64decode(x.encode("ascii"))))
|
41 |
+
return image
|
42 |
+
except Exception as e:
|
43 |
+
raise RuntimeError(
|
44 |
+
f"Encountered an error when loading image from bytes starting "
|
45 |
+
f"with '{x[:20]}'. Expected either a PIL.Image.Image or a base64 "
|
46 |
+
f"encoded string of bytes."
|
47 |
+
) from e
|
48 |
+
|
49 |
+
|
50 |
+
def serialize_image_to_byte_str(im: Image.Image, info: SerializationInfo) -> str:
|
51 |
+
if hasattr(info, "context"):
|
52 |
+
context = info.context or {}
|
53 |
+
else:
|
54 |
+
context = {}
|
55 |
+
|
56 |
+
stream = io.BytesIO()
|
57 |
+
im_format = im.format or "PNG"
|
58 |
+
im.save(stream, format=im_format)
|
59 |
+
im_b64 = base64.b64encode(stream.getvalue()).decode("ascii")
|
60 |
+
if context and (max_image_b64_len := context.get("max_image_b64_len")):
|
61 |
+
return im_b64[:max_image_b64_len] + "..."
|
62 |
+
return im_b64
|
63 |
+
|
64 |
+
|
65 |
+
# A normal PIL image that supports serialization to b64 bytes string
|
66 |
+
SerializableImage = Annotated[
|
67 |
+
Image.Image,
|
68 |
+
BeforeValidator(maybe_load_image_from_str_or_bytes),
|
69 |
+
PlainSerializer(serialize_image_to_byte_str),
|
70 |
+
]
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/__init__.py
ADDED
File without changes
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (196 Bytes). View file
|
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/__pycache__/base.cpython-311.pyc
ADDED
Binary file (1.49 kB). View file
|
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/__pycache__/utils.cpython-311.pyc
ADDED
Binary file (476 Bytes). View file
|
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/base.py
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Optional
|
2 |
+
|
3 |
+
from pydantic import Field
|
4 |
+
|
5 |
+
from mistral_common.base import MistralBase
|
6 |
+
|
7 |
+
|
8 |
+
class UsageInfo(MistralBase):
|
9 |
+
prompt_tokens: int = 0
|
10 |
+
total_tokens: int = 0
|
11 |
+
completion_tokens: Optional[int] = 0
|
12 |
+
|
13 |
+
|
14 |
+
class BaseCompletionRequest(MistralBase):
|
15 |
+
temperature: float = Field(default=0.7, ge=0.0, le=1.0)
|
16 |
+
top_p: float = Field(default=1.0, ge=0.0, le=1.0)
|
17 |
+
max_tokens: Optional[int] = Field(default=None, ge=0)
|
18 |
+
random_seed: Optional[int] = Field(default=None, ge=0)
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/__init__.py
ADDED
File without changes
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/__pycache__/normalize.cpython-311.pyc
ADDED
Binary file (15.2 kB). View file
|
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/__pycache__/request.cpython-311.pyc
ADDED
Binary file (2.14 kB). View file
|
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/__pycache__/tool_calls.cpython-311.pyc
ADDED
Binary file (3.07 kB). View file
|
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/__pycache__/validator.cpython-311.pyc
ADDED
Binary file (16.9 kB). View file
|
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/messages.py
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from enum import Enum
|
2 |
+
from typing import List, Literal, Optional, TypeVar, Union
|
3 |
+
|
4 |
+
from pydantic import ConfigDict, Field
|
5 |
+
from typing_extensions import Annotated, TypeAlias
|
6 |
+
|
7 |
+
from mistral_common.base import MistralBase
|
8 |
+
from mistral_common.multimodal import SerializableImage
|
9 |
+
from mistral_common.protocol.instruct.tool_calls import ToolCall
|
10 |
+
|
11 |
+
|
12 |
+
class ChunkTypes(str, Enum):
|
13 |
+
text = "text"
|
14 |
+
image = "image"
|
15 |
+
image_url = "image_url"
|
16 |
+
|
17 |
+
|
18 |
+
class BaseContentChunk(MistralBase):
|
19 |
+
type: Literal[ChunkTypes.text, ChunkTypes.image, ChunkTypes.image_url]
|
20 |
+
|
21 |
+
|
22 |
+
class ImageChunk(BaseContentChunk):
|
23 |
+
type: Literal[ChunkTypes.image] = ChunkTypes.image
|
24 |
+
image: SerializableImage
|
25 |
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
26 |
+
|
27 |
+
|
28 |
+
class ImageURL(MistralBase):
|
29 |
+
url: str
|
30 |
+
detail: Optional[str] = None
|
31 |
+
|
32 |
+
|
33 |
+
class ImageURLChunk(BaseContentChunk):
|
34 |
+
"""
|
35 |
+
{"type":"image_url","image_url":{"url":"data:image/png;base64,iVBORw0
|
36 |
+
"""
|
37 |
+
|
38 |
+
type: Literal[ChunkTypes.image_url] = ChunkTypes.image_url
|
39 |
+
image_url: Union[ImageURL, str]
|
40 |
+
|
41 |
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
42 |
+
|
43 |
+
def get_url(self) -> str:
|
44 |
+
if isinstance(self.image_url, ImageURL):
|
45 |
+
return self.image_url.url
|
46 |
+
return self.image_url
|
47 |
+
|
48 |
+
|
49 |
+
class TextChunk(BaseContentChunk):
|
50 |
+
type: Literal[ChunkTypes.text] = ChunkTypes.text
|
51 |
+
text: str
|
52 |
+
|
53 |
+
|
54 |
+
ContentChunk = Annotated[Union[TextChunk, ImageChunk, ImageURLChunk], Field(discriminator="type")]
|
55 |
+
|
56 |
+
|
57 |
+
class Roles(str, Enum):
|
58 |
+
system = "system"
|
59 |
+
user = "user"
|
60 |
+
assistant = "assistant"
|
61 |
+
tool = "tool"
|
62 |
+
|
63 |
+
|
64 |
+
class BaseMessage(MistralBase):
|
65 |
+
role: Literal[Roles.system, Roles.user, Roles.assistant, Roles.tool]
|
66 |
+
|
67 |
+
|
68 |
+
class UserMessage(BaseMessage):
|
69 |
+
role: Literal[Roles.user] = Roles.user
|
70 |
+
content: Union[str, List[ContentChunk]]
|
71 |
+
|
72 |
+
|
73 |
+
class SystemMessage(BaseMessage):
|
74 |
+
role: Literal[Roles.system] = Roles.system
|
75 |
+
content: Union[str, List[ContentChunk]]
|
76 |
+
|
77 |
+
|
78 |
+
class AssistantMessage(BaseMessage):
|
79 |
+
role: Literal[Roles.assistant] = Roles.assistant
|
80 |
+
content: Optional[str] = None
|
81 |
+
tool_calls: Optional[List[ToolCall]] = None
|
82 |
+
prefix: bool = False
|
83 |
+
|
84 |
+
|
85 |
+
class FinetuningAssistantMessage(AssistantMessage):
|
86 |
+
weight: Optional[float] = None
|
87 |
+
|
88 |
+
|
89 |
+
class ToolMessage(BaseMessage):
|
90 |
+
content: str
|
91 |
+
role: Literal[Roles.tool] = Roles.tool
|
92 |
+
tool_call_id: Optional[str] = None
|
93 |
+
|
94 |
+
# Deprecated in V3 tokenization
|
95 |
+
name: Optional[str] = None
|
96 |
+
|
97 |
+
|
98 |
+
ChatMessage = Annotated[Union[SystemMessage, UserMessage, AssistantMessage, ToolMessage], Field(discriminator="role")]
|
99 |
+
|
100 |
+
FinetuningMessage = Annotated[
|
101 |
+
Union[SystemMessage, UserMessage, FinetuningAssistantMessage, ToolMessage],
|
102 |
+
Field(discriminator="role"),
|
103 |
+
]
|
104 |
+
|
105 |
+
ChatMessageType = TypeVar("ChatMessageType", bound=ChatMessage)
|
106 |
+
|
107 |
+
# Used for type hinting in generic classes where we might override the message types
|
108 |
+
UserMessageType = TypeVar("UserMessageType", bound=UserMessage)
|
109 |
+
AssistantMessageType = TypeVar("AssistantMessageType", bound=AssistantMessage)
|
110 |
+
ToolMessageType = TypeVar("ToolMessageType", bound=ToolMessage)
|
111 |
+
SystemMessageType = TypeVar("SystemMessageType", bound=SystemMessage)
|
112 |
+
|
113 |
+
UATS: TypeAlias = Union[UserMessageType, AssistantMessageType, ToolMessageType, SystemMessageType]
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/normalize.py
ADDED
@@ -0,0 +1,265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
from typing import Generic, List, Optional, Sequence, Type, Union
|
3 |
+
|
4 |
+
from mistral_common.protocol.instruct.messages import (
|
5 |
+
UATS,
|
6 |
+
AssistantMessage,
|
7 |
+
AssistantMessageType,
|
8 |
+
ContentChunk,
|
9 |
+
FinetuningAssistantMessage,
|
10 |
+
Roles,
|
11 |
+
SystemMessage,
|
12 |
+
SystemMessageType,
|
13 |
+
TextChunk,
|
14 |
+
ToolMessage,
|
15 |
+
ToolMessageType,
|
16 |
+
UserMessage,
|
17 |
+
UserMessageType,
|
18 |
+
)
|
19 |
+
from mistral_common.protocol.instruct.request import ChatCompletionRequest
|
20 |
+
from mistral_common.protocol.instruct.tool_calls import FunctionCall, Tool, ToolCall
|
21 |
+
from mistral_common.tokens.instruct.request import InstructRequest
|
22 |
+
from mistral_common.tokens.tokenizers.base import InstructRequestType, TokenizerVersion
|
23 |
+
|
24 |
+
|
25 |
+
class InstructRequestNormalizer(
|
26 |
+
Generic[UserMessageType, AssistantMessageType, ToolMessageType, SystemMessageType, InstructRequestType]
|
27 |
+
):
|
28 |
+
"""
|
29 |
+
Takes a ChatCompletionRequest and normalizes it into an InstructRequest.
|
30 |
+
|
31 |
+
The normalization process does several things such as:
|
32 |
+
- Aggregate consecutive messages of the same role
|
33 |
+
- Aggregate system prompts
|
34 |
+
- Normalize json content
|
35 |
+
- Normalize tool calls
|
36 |
+
"""
|
37 |
+
|
38 |
+
system_prompt_in_begin: bool = False
|
39 |
+
|
40 |
+
def __init__(
|
41 |
+
self,
|
42 |
+
user_message_class: Type[UserMessageType],
|
43 |
+
assistant_message_class: Type[AssistantMessageType],
|
44 |
+
tool_message_class: Type[ToolMessageType],
|
45 |
+
system_message_class: Type[SystemMessageType],
|
46 |
+
instruct_request_class: Type[InstructRequestType],
|
47 |
+
):
|
48 |
+
self._user_message_class = user_message_class
|
49 |
+
self._assistant_message_class = assistant_message_class
|
50 |
+
self._tool_message_class = tool_message_class
|
51 |
+
self._instruct_request_class = instruct_request_class
|
52 |
+
# this is unused but makes creation nicer
|
53 |
+
self._system_message_class = system_message_class
|
54 |
+
|
55 |
+
@staticmethod
|
56 |
+
def normalizer() -> "InstructRequestNormalizer":
|
57 |
+
return InstructRequestNormalizer(
|
58 |
+
UserMessage,
|
59 |
+
AssistantMessage,
|
60 |
+
ToolMessage,
|
61 |
+
SystemMessage,
|
62 |
+
InstructRequest[UATS, Tool],
|
63 |
+
)
|
64 |
+
|
65 |
+
def _normalize_json_content(self, content: Optional[str]) -> str:
|
66 |
+
if content is None or len(content) == 0:
|
67 |
+
return "{}"
|
68 |
+
|
69 |
+
try:
|
70 |
+
parsed_json = json.loads(content)
|
71 |
+
normalized_content = json.dumps(parsed_json, ensure_ascii=False)
|
72 |
+
except json.JSONDecodeError:
|
73 |
+
normalized_content = content
|
74 |
+
return normalized_content
|
75 |
+
|
76 |
+
def _aggregate_content_chunks(self, content: Union[str, List[TextChunk]], chunk_join_str: str = "\n\n") -> str:
|
77 |
+
if isinstance(content, list):
|
78 |
+
return chunk_join_str.join([chunk.text for chunk in content])
|
79 |
+
else:
|
80 |
+
return content
|
81 |
+
|
82 |
+
def _aggregate_system_prompts(self, request: ChatCompletionRequest[UATS]) -> Optional[str]:
|
83 |
+
system_prompt: List[str] = []
|
84 |
+
|
85 |
+
for message in request.messages:
|
86 |
+
if message.role == Roles.system and message.content:
|
87 |
+
system_prompt.append(self._aggregate_content_chunks(message.content))
|
88 |
+
|
89 |
+
return "\n\n".join(system_prompt) if len(system_prompt) else None
|
90 |
+
|
91 |
+
def _aggregate_tool_messages(self, messages: List[UATS]) -> List[ToolMessageType]:
|
92 |
+
"""
|
93 |
+
We currently do not do any aggregation for tool messages, but we normalize the json content
|
94 |
+
"""
|
95 |
+
tool_messages: List[ToolMessageType] = []
|
96 |
+
for message in messages:
|
97 |
+
assert isinstance(message, self._tool_message_class), "Expected tool message"
|
98 |
+
content = self._aggregate_content_chunks(message.content)
|
99 |
+
normalized_content = self._normalize_json_content(content)
|
100 |
+
tool_messages.append(
|
101 |
+
self._tool_message_class(
|
102 |
+
content=normalized_content, tool_call_id=message.tool_call_id, name=message.name
|
103 |
+
)
|
104 |
+
)
|
105 |
+
|
106 |
+
return tool_messages
|
107 |
+
|
108 |
+
def _normalize_tool_call(self, tool_call: ToolCall) -> ToolCall:
|
109 |
+
normalized_function_aruments = self._normalize_json_content(tool_call.function.arguments)
|
110 |
+
return ToolCall(
|
111 |
+
function=FunctionCall(name=tool_call.function.name, arguments=normalized_function_aruments),
|
112 |
+
id=tool_call.id,
|
113 |
+
)
|
114 |
+
|
115 |
+
def _aggregate_assistant_messages(self, messages: List[UATS]) -> AssistantMessageType:
|
116 |
+
aggregated_content: List[str] = []
|
117 |
+
tool_calls: List[ToolCall] = []
|
118 |
+
prefix: bool = False
|
119 |
+
weight: Optional[float] = None
|
120 |
+
for message in messages:
|
121 |
+
assert isinstance(message, self._assistant_message_class), "Expected assistant message"
|
122 |
+
if message.tool_calls is not None and len(message.tool_calls) > 0:
|
123 |
+
for tool_call in message.tool_calls:
|
124 |
+
normalized_tool_call = self._normalize_tool_call(tool_call)
|
125 |
+
tool_calls.append(normalized_tool_call)
|
126 |
+
elif message.content:
|
127 |
+
aggregated_content.append(self._aggregate_content_chunks(message.content))
|
128 |
+
prefix |= message.prefix
|
129 |
+
if isinstance(message, FinetuningAssistantMessage):
|
130 |
+
# Only FinetuningAssistantMessage can be weighted
|
131 |
+
if weight is not None:
|
132 |
+
assert (
|
133 |
+
weight == message.weight
|
134 |
+
), "Expected weights of aggregated FinetuningAssistantMessage to be equal"
|
135 |
+
weight = message.weight
|
136 |
+
|
137 |
+
aggregated_message = self._assistant_message_class(
|
138 |
+
content="\n\n".join(aggregated_content) if len(aggregated_content) else None,
|
139 |
+
tool_calls=tool_calls or None,
|
140 |
+
prefix=prefix,
|
141 |
+
)
|
142 |
+
|
143 |
+
if weight is not None and hasattr(aggregated_message, "weight"):
|
144 |
+
aggregated_message.weight = weight
|
145 |
+
return aggregated_message
|
146 |
+
|
147 |
+
def _aggregate_user_messages(self, messages: List[UATS]) -> UserMessageType:
|
148 |
+
"""
|
149 |
+
Just coalesce neighboring blocks of text
|
150 |
+
"""
|
151 |
+
all_content: List[ContentChunk] = []
|
152 |
+
text_chunks: List[str] = []
|
153 |
+
for message in messages:
|
154 |
+
assert isinstance(message, self._user_message_class), f"Expected user message got {type(message)}"
|
155 |
+
if isinstance(message.content, str):
|
156 |
+
text_chunks.append(message.content)
|
157 |
+
else: # it's a List[ContentChunk]
|
158 |
+
for chunk in message.content:
|
159 |
+
if isinstance(chunk, TextChunk):
|
160 |
+
text_chunks.append(chunk.text)
|
161 |
+
else:
|
162 |
+
if text_chunks:
|
163 |
+
all_content.append(TextChunk(text="\n\n".join(text_chunks)))
|
164 |
+
text_chunks = []
|
165 |
+
all_content.append(chunk)
|
166 |
+
|
167 |
+
text_content = "\n\n".join(text_chunks) if text_chunks else ""
|
168 |
+
|
169 |
+
if not all_content:
|
170 |
+
# if no ContentChunk was passed, we return content as a str
|
171 |
+
return self._user_message_class(content=text_content)
|
172 |
+
|
173 |
+
if text_content:
|
174 |
+
# else we return a List of content chunks
|
175 |
+
all_content.append(TextChunk(text=text_content))
|
176 |
+
|
177 |
+
return self._user_message_class(content=all_content)
|
178 |
+
|
179 |
+
def _aggregate_role(self, messages: List[UATS], role: Optional[Roles]) -> Sequence[UATS]:
|
180 |
+
if role == Roles.tool:
|
181 |
+
return self._aggregate_tool_messages(messages)
|
182 |
+
elif role == Roles.assistant:
|
183 |
+
return [self._aggregate_assistant_messages(messages)]
|
184 |
+
elif role == Roles.user:
|
185 |
+
return [self._aggregate_user_messages(messages)]
|
186 |
+
else: # System messages are ignored
|
187 |
+
return []
|
188 |
+
|
189 |
+
def _aggregate_messages(self, request: ChatCompletionRequest[UATS]) -> List[UATS]:
|
190 |
+
aggregated_messages: List[UATS] = []
|
191 |
+
messages_to_aggregate: List[UATS] = []
|
192 |
+
current_role: Optional[Roles] = None
|
193 |
+
current_weight: Optional[float] = None
|
194 |
+
|
195 |
+
# Collect consecutive lists of messages with the same role and weight
|
196 |
+
for message in request.messages:
|
197 |
+
new_weight = getattr(message, "weight", None)
|
198 |
+
if current_role != message.role or (new_weight != current_weight):
|
199 |
+
aggregated_messages.extend(self._aggregate_role(messages_to_aggregate, current_role))
|
200 |
+
messages_to_aggregate.clear()
|
201 |
+
current_weight = new_weight
|
202 |
+
current_role = message.role
|
203 |
+
messages_to_aggregate.append(message)
|
204 |
+
|
205 |
+
# Add the last set of messages
|
206 |
+
aggregated_messages.extend(self._aggregate_role(messages_to_aggregate, current_role))
|
207 |
+
|
208 |
+
# If the first message is not a user message, or we didnt aggregate
|
209 |
+
# anything (all system messages) for example, add an empty user message
|
210 |
+
if len(aggregated_messages) == 0 or (
|
211 |
+
not self.system_prompt_in_begin and aggregated_messages[0].role != Roles.user
|
212 |
+
):
|
213 |
+
aggregated_messages.insert(0, self._user_message_class(content=""))
|
214 |
+
|
215 |
+
return aggregated_messages
|
216 |
+
|
217 |
+
def from_chat_completion_request(self, request: ChatCompletionRequest[UATS]) -> InstructRequestType:
|
218 |
+
system_prompt = self._aggregate_system_prompts(request)
|
219 |
+
messages = self._aggregate_messages(request)
|
220 |
+
|
221 |
+
return self._instruct_request_class(
|
222 |
+
messages=messages, system_prompt=system_prompt, available_tools=request.tools
|
223 |
+
)
|
224 |
+
|
225 |
+
|
226 |
+
class InstructRequestNormalizerV7(InstructRequestNormalizer):
|
227 |
+
system_prompt_in_begin: bool = True
|
228 |
+
|
229 |
+
@staticmethod
|
230 |
+
def normalizer() -> "InstructRequestNormalizerV7":
|
231 |
+
return InstructRequestNormalizerV7(
|
232 |
+
UserMessage,
|
233 |
+
AssistantMessage,
|
234 |
+
ToolMessage,
|
235 |
+
SystemMessage,
|
236 |
+
InstructRequest[UATS, Tool],
|
237 |
+
)
|
238 |
+
|
239 |
+
def _aggregate_role(self, messages: List[UATS], role: Optional[Roles]) -> Sequence[UATS]:
|
240 |
+
if role == Roles.tool:
|
241 |
+
return self._aggregate_tool_messages(messages)
|
242 |
+
elif role == Roles.assistant:
|
243 |
+
return [self._aggregate_assistant_messages(messages)]
|
244 |
+
elif role == Roles.user:
|
245 |
+
return [self._aggregate_user_messages(messages)]
|
246 |
+
elif role == Roles.system:
|
247 |
+
return messages
|
248 |
+
else:
|
249 |
+
assert role is None and len(messages) == 0
|
250 |
+
return []
|
251 |
+
|
252 |
+
def _aggregate_system_prompts(self, request: ChatCompletionRequest[UATS]) -> Optional[str]:
|
253 |
+
raise NotImplementedError("We should not aggregate system prompts")
|
254 |
+
|
255 |
+
def from_chat_completion_request(self, request: ChatCompletionRequest[UATS]) -> InstructRequestType: # type: ignore[type-var]
|
256 |
+
messages = self._aggregate_messages(request)
|
257 |
+
return self._instruct_request_class(messages=messages, system_prompt=None, available_tools=request.tools) # type: ignore[no-any-return]
|
258 |
+
|
259 |
+
|
260 |
+
def normalizer_for_tokenizer_version(version: TokenizerVersion) -> InstructRequestNormalizer:
|
261 |
+
if version in {TokenizerVersion.v1, TokenizerVersion.v2, TokenizerVersion.v3}:
|
262 |
+
return InstructRequestNormalizer.normalizer()
|
263 |
+
elif version == TokenizerVersion.v7:
|
264 |
+
return InstructRequestNormalizerV7.normalizer()
|
265 |
+
raise ValueError(f"Unknown tokenizer version {version}")
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/request.py
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from enum import Enum
|
2 |
+
from typing import Generic, List, Optional
|
3 |
+
|
4 |
+
from pydantic import Field
|
5 |
+
|
6 |
+
from mistral_common.base import MistralBase
|
7 |
+
from mistral_common.protocol.base import BaseCompletionRequest
|
8 |
+
from mistral_common.protocol.instruct.messages import ChatMessageType
|
9 |
+
from mistral_common.protocol.instruct.tool_calls import Tool, ToolChoice
|
10 |
+
|
11 |
+
|
12 |
+
class ResponseFormats(str, Enum):
|
13 |
+
text: str = "text"
|
14 |
+
json: str = "json_object"
|
15 |
+
|
16 |
+
|
17 |
+
class ResponseFormat(MistralBase):
|
18 |
+
type: ResponseFormats = ResponseFormats.text
|
19 |
+
|
20 |
+
|
21 |
+
class ChatCompletionRequest(BaseCompletionRequest, Generic[ChatMessageType]):
|
22 |
+
model: Optional[str] = None
|
23 |
+
messages: List[ChatMessageType]
|
24 |
+
response_format: ResponseFormat = Field(default_factory=ResponseFormat)
|
25 |
+
tools: Optional[List[Tool]] = None
|
26 |
+
tool_choice: ToolChoice = ToolChoice.auto
|
27 |
+
truncate_for_context_length: bool = False
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/response.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import time
|
2 |
+
from enum import Enum
|
3 |
+
from typing import List, Optional
|
4 |
+
|
5 |
+
from pydantic import Field
|
6 |
+
|
7 |
+
from mistral_common.base import MistralBase
|
8 |
+
from mistral_common.protocol.base import UsageInfo
|
9 |
+
from mistral_common.protocol.instruct.tool_calls import ToolCall
|
10 |
+
from mistral_common.protocol.utils import random_uuid
|
11 |
+
|
12 |
+
|
13 |
+
class FinishReason(str, Enum):
|
14 |
+
stop: str = "stop"
|
15 |
+
length: str = "length"
|
16 |
+
model_length: str = "model_length"
|
17 |
+
error: str = "error"
|
18 |
+
tool_call: str = "tool_calls"
|
19 |
+
|
20 |
+
|
21 |
+
class ChatCompletionTokenLogprobs(MistralBase):
|
22 |
+
token: str
|
23 |
+
logprob: float
|
24 |
+
bytes: List[int]
|
25 |
+
|
26 |
+
|
27 |
+
class ChatCompletionResponseChoiceLogprobs(MistralBase):
|
28 |
+
content: List[ChatCompletionTokenLogprobs]
|
29 |
+
|
30 |
+
|
31 |
+
class DeltaMessage(MistralBase):
|
32 |
+
role: Optional[str] = None
|
33 |
+
content: Optional[str] = None
|
34 |
+
tool_calls: Optional[List[ToolCall]] = None
|
35 |
+
|
36 |
+
|
37 |
+
class ChatCompletionResponseChoice(MistralBase):
|
38 |
+
index: int
|
39 |
+
message: DeltaMessage
|
40 |
+
finish_reason: Optional[FinishReason] = None
|
41 |
+
logprobs: Optional[ChatCompletionResponseChoiceLogprobs] = None
|
42 |
+
|
43 |
+
|
44 |
+
class ChatCompletionResponse(MistralBase):
|
45 |
+
id: str = Field(default_factory=lambda: f"chatcmpl-{random_uuid()}")
|
46 |
+
object: str = "chat.completion"
|
47 |
+
created: int = Field(default_factory=lambda: int(time.time()))
|
48 |
+
model: str
|
49 |
+
choices: List[ChatCompletionResponseChoice]
|
50 |
+
usage: UsageInfo
|
51 |
+
|
52 |
+
|
53 |
+
class ChatCompletionResponseStreamChoice(MistralBase):
|
54 |
+
index: int
|
55 |
+
delta: DeltaMessage
|
56 |
+
finish_reason: Optional[FinishReason] = None
|
57 |
+
logprobs: Optional[ChatCompletionResponseChoiceLogprobs] = None
|
58 |
+
|
59 |
+
|
60 |
+
class ChatCompletionStreamResponse(MistralBase):
|
61 |
+
id: str = Field(default_factory=lambda: f"chatcmpl-{random_uuid()}")
|
62 |
+
object: str = "chat.completion.chunk"
|
63 |
+
created: int = Field(default_factory=lambda: int(time.time()))
|
64 |
+
model: str
|
65 |
+
choices: List[ChatCompletionResponseStreamChoice]
|
66 |
+
usage: Optional[UsageInfo] = None
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/tool_calls.py
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
from enum import Enum
|
3 |
+
from typing import Any, Dict, TypeVar, Union
|
4 |
+
|
5 |
+
from pydantic import field_validator
|
6 |
+
|
7 |
+
from mistral_common.base import MistralBase
|
8 |
+
|
9 |
+
|
10 |
+
class Function(MistralBase):
|
11 |
+
name: str
|
12 |
+
description: str = ""
|
13 |
+
parameters: Dict[str, Any]
|
14 |
+
|
15 |
+
|
16 |
+
class ToolTypes(str, Enum):
|
17 |
+
function = "function"
|
18 |
+
|
19 |
+
|
20 |
+
class ToolChoice(str, Enum):
|
21 |
+
auto: str = "auto"
|
22 |
+
none: str = "none"
|
23 |
+
any: str = "any"
|
24 |
+
|
25 |
+
|
26 |
+
class Tool(MistralBase):
|
27 |
+
type: ToolTypes = ToolTypes.function
|
28 |
+
function: Function
|
29 |
+
|
30 |
+
|
31 |
+
class FunctionCall(MistralBase):
|
32 |
+
name: str
|
33 |
+
arguments: str
|
34 |
+
|
35 |
+
@field_validator("arguments", mode="before")
|
36 |
+
def validate_arguments(cls, v: Union[str, Dict[str, Any]]) -> str:
|
37 |
+
"""
|
38 |
+
This is for backward compatibility
|
39 |
+
"""
|
40 |
+
if isinstance(v, dict):
|
41 |
+
return json.dumps(v)
|
42 |
+
return v
|
43 |
+
|
44 |
+
|
45 |
+
class ToolCall(MistralBase):
|
46 |
+
id: str = "null" # required for V3 tokenization
|
47 |
+
type: ToolTypes = ToolTypes.function
|
48 |
+
function: FunctionCall
|
49 |
+
|
50 |
+
|
51 |
+
ToolType = TypeVar("ToolType", bound=Tool)
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/instruct/validator.py
ADDED
@@ -0,0 +1,328 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import re
|
2 |
+
from enum import Enum
|
3 |
+
from typing import Generic, List
|
4 |
+
|
5 |
+
from jsonschema import Draft7Validator, SchemaError
|
6 |
+
|
7 |
+
from mistral_common.exceptions import (
|
8 |
+
InvalidAssistantMessageException,
|
9 |
+
InvalidFunctionCallException,
|
10 |
+
InvalidMessageStructureException,
|
11 |
+
InvalidRequestException,
|
12 |
+
InvalidSystemPromptException,
|
13 |
+
InvalidToolException,
|
14 |
+
InvalidToolMessageException,
|
15 |
+
InvalidToolSchemaException,
|
16 |
+
)
|
17 |
+
from mistral_common.protocol.instruct.messages import (
|
18 |
+
UATS,
|
19 |
+
AssistantMessage,
|
20 |
+
AssistantMessageType,
|
21 |
+
FinetuningAssistantMessage,
|
22 |
+
Roles,
|
23 |
+
SystemMessageType,
|
24 |
+
ToolMessageType,
|
25 |
+
UserMessageType,
|
26 |
+
)
|
27 |
+
from mistral_common.protocol.instruct.request import ChatCompletionRequest
|
28 |
+
from mistral_common.protocol.instruct.tool_calls import (
|
29 |
+
Function,
|
30 |
+
FunctionCall,
|
31 |
+
Tool,
|
32 |
+
ToolCall,
|
33 |
+
)
|
34 |
+
|
35 |
+
|
36 |
+
class ValidationMode(Enum):
|
37 |
+
serving = "serving"
|
38 |
+
finetuning = "finetuning"
|
39 |
+
test = "test"
|
40 |
+
|
41 |
+
|
42 |
+
class MistralRequestValidator(Generic[UserMessageType, AssistantMessageType, ToolMessageType, SystemMessageType]):
|
43 |
+
def __init__(self, mode: ValidationMode = ValidationMode.test):
|
44 |
+
self._mode = mode
|
45 |
+
|
46 |
+
def validate_messages(self, messages: List[UATS]) -> None:
|
47 |
+
"""
|
48 |
+
Validates the list of messages
|
49 |
+
"""
|
50 |
+
self._validate_message_list_structure(messages)
|
51 |
+
self._validate_message_list_content(messages)
|
52 |
+
|
53 |
+
def validate_request(self, request: ChatCompletionRequest) -> ChatCompletionRequest[UATS]:
|
54 |
+
"""
|
55 |
+
Validates the request
|
56 |
+
"""
|
57 |
+
|
58 |
+
if self._mode == ValidationMode.serving:
|
59 |
+
if request.model is None:
|
60 |
+
raise InvalidRequestException("Model name parameter is required for serving mode")
|
61 |
+
|
62 |
+
# Validate the messages
|
63 |
+
self.validate_messages(request.messages)
|
64 |
+
|
65 |
+
# Validate the tools
|
66 |
+
self._validate_tools(request.tools or [])
|
67 |
+
|
68 |
+
return request
|
69 |
+
|
70 |
+
def _validate_function(self, function: Function) -> None:
|
71 |
+
"""
|
72 |
+
Checks:
|
73 |
+
- That the function schema is valid
|
74 |
+
"""
|
75 |
+
try:
|
76 |
+
Draft7Validator.check_schema(function.parameters)
|
77 |
+
except SchemaError as e:
|
78 |
+
raise InvalidToolSchemaException(f"Invalid tool schema: {e.message}")
|
79 |
+
|
80 |
+
if not re.match(r"^[a-zA-Z0-9_-]{1,64}$", function.name):
|
81 |
+
raise InvalidToolException(
|
82 |
+
f"Function name was {function.name} but must be a-z, A-Z, 0-9, "
|
83 |
+
"or contain underscores and dashes, with a maximum length of 64."
|
84 |
+
)
|
85 |
+
|
86 |
+
def _validate_tools(self, tools: List[Tool]) -> None:
|
87 |
+
"""
|
88 |
+
Checks:
|
89 |
+
- That the tool schemas are valid
|
90 |
+
"""
|
91 |
+
|
92 |
+
for tool in tools:
|
93 |
+
self._validate_function(tool.function)
|
94 |
+
|
95 |
+
def _validate_user_message(self, message: UserMessageType) -> None:
|
96 |
+
pass
|
97 |
+
|
98 |
+
def _validate_tool_message(self, message: ToolMessageType) -> None:
|
99 |
+
"""
|
100 |
+
Checks:
|
101 |
+
- The tool name is valid
|
102 |
+
"""
|
103 |
+
if message.name is not None:
|
104 |
+
if not re.match(r"^[a-zA-Z0-9_-]{1,64}$", message.name):
|
105 |
+
raise InvalidToolMessageException(
|
106 |
+
f"Function name was {message.name} but must be a-z, A-Z, 0-9, "
|
107 |
+
"or contain underscores and dashes, with a maximum length of 64."
|
108 |
+
)
|
109 |
+
|
110 |
+
def _validate_system_message(self, message: SystemMessageType) -> None:
|
111 |
+
"""
|
112 |
+
Checks:
|
113 |
+
- That the system prompt has content
|
114 |
+
"""
|
115 |
+
if message.content is None:
|
116 |
+
raise InvalidSystemPromptException("System prompt must have content")
|
117 |
+
|
118 |
+
def _validate_function_call(self, function_call: FunctionCall) -> None:
|
119 |
+
"""
|
120 |
+
Checks:
|
121 |
+
- That the function call has a valid name
|
122 |
+
"""
|
123 |
+
if not re.match(r"^[a-zA-Z0-9_-]{1,64}$", function_call.name):
|
124 |
+
raise InvalidFunctionCallException(
|
125 |
+
f"Function name was {function_call.name} but must be a-z, A-Z, 0-9, "
|
126 |
+
"or contain underscores and dashes, with a maximum length of 64."
|
127 |
+
)
|
128 |
+
|
129 |
+
def _validate_tool_call(self, tool_call: ToolCall, is_last_message: bool) -> None:
|
130 |
+
"""
|
131 |
+
Checks:
|
132 |
+
- That the tool call has a valid function
|
133 |
+
"""
|
134 |
+
|
135 |
+
self._validate_function_call(tool_call.function)
|
136 |
+
|
137 |
+
def _validate_assistant_message(self, message: AssistantMessageType, is_last_message: bool = False) -> None:
|
138 |
+
"""
|
139 |
+
Checks:
|
140 |
+
- That the assistant message has either text or tool_calls, but not both
|
141 |
+
- That the tool calls are valid
|
142 |
+
"""
|
143 |
+
|
144 |
+
# Validate that the message has either text or tool_calls
|
145 |
+
# but not both and not neither.
|
146 |
+
if bool(message.content) == bool(message.tool_calls):
|
147 |
+
raise InvalidAssistantMessageException(
|
148 |
+
"Assistant message must have either content or tool_calls, but not both."
|
149 |
+
)
|
150 |
+
|
151 |
+
# If we have tool calls, validate them
|
152 |
+
if message.tool_calls is not None:
|
153 |
+
# Validate that the tool calls are valid
|
154 |
+
for tool_call in message.tool_calls:
|
155 |
+
self._validate_tool_call(tool_call, is_last_message=is_last_message)
|
156 |
+
|
157 |
+
if self._mode == ValidationMode.finetuning and isinstance(message, FinetuningAssistantMessage):
|
158 |
+
if message.weight is not None and message.weight not in [0, 1]:
|
159 |
+
raise InvalidAssistantMessageException("Assistant message weight must be either 0 or 1")
|
160 |
+
|
161 |
+
if message.prefix:
|
162 |
+
if not is_last_message:
|
163 |
+
raise InvalidAssistantMessageException("Assistant message with prefix True must be last message")
|
164 |
+
# note : we already validate that assistant messsage has content 3 lines up.
|
165 |
+
|
166 |
+
def _validate_tool_calls_followed_by_tool_messages(self, messages: List[UATS]) -> None:
|
167 |
+
"""
|
168 |
+
Checks:
|
169 |
+
- That the number of tool calls and tool messages are the same
|
170 |
+
- That the tool calls are followed by tool messages
|
171 |
+
"""
|
172 |
+
prev_role = None
|
173 |
+
expected_tool_messages = 0
|
174 |
+
for message in messages:
|
175 |
+
if prev_role is None:
|
176 |
+
prev_role = message.role
|
177 |
+
continue
|
178 |
+
|
179 |
+
if message.role == Roles.tool:
|
180 |
+
expected_tool_messages -= 1
|
181 |
+
elif message.role == Roles.assistant:
|
182 |
+
# if we have an assistant message and we have not received all the function calls
|
183 |
+
# we need to raise an exception
|
184 |
+
if expected_tool_messages != 0:
|
185 |
+
raise InvalidMessageStructureException("Not the same number of function calls and responses")
|
186 |
+
|
187 |
+
if message.tool_calls is not None:
|
188 |
+
# Validate that the number of function calls and responses are the same
|
189 |
+
expected_tool_messages = len(message.tool_calls)
|
190 |
+
|
191 |
+
prev_role = message.role
|
192 |
+
|
193 |
+
if expected_tool_messages != 0 and self._mode == ValidationMode.serving:
|
194 |
+
raise InvalidMessageStructureException("Not the same number of function calls and responses")
|
195 |
+
elif expected_tool_messages < 0 and self._mode == ValidationMode.finetuning:
|
196 |
+
raise InvalidMessageStructureException("More tool responses than tool calls")
|
197 |
+
|
198 |
+
def _validate_message_order(self, messages: List[UATS]) -> None:
|
199 |
+
"""
|
200 |
+
Validates the order of the messages, for example user -> assistant -> user -> assistant -> ...
|
201 |
+
"""
|
202 |
+
previous_role = None
|
203 |
+
for message in messages:
|
204 |
+
current_role = message.role
|
205 |
+
|
206 |
+
if previous_role is not None:
|
207 |
+
if previous_role == Roles.system:
|
208 |
+
expected_roles = {Roles.user, Roles.assistant, Roles.system}
|
209 |
+
elif previous_role == Roles.user:
|
210 |
+
expected_roles = {Roles.assistant, Roles.system, Roles.user}
|
211 |
+
elif previous_role == Roles.assistant:
|
212 |
+
expected_roles = {Roles.assistant, Roles.user, Roles.tool}
|
213 |
+
elif previous_role == Roles.tool:
|
214 |
+
expected_roles = {Roles.assistant, Roles.tool}
|
215 |
+
|
216 |
+
if current_role not in expected_roles:
|
217 |
+
raise InvalidMessageStructureException(
|
218 |
+
f"Unexpected role '{current_role}' after role '{previous_role}'"
|
219 |
+
)
|
220 |
+
|
221 |
+
previous_role = current_role
|
222 |
+
|
223 |
+
def _validate_last_message(self, message: UATS) -> None:
|
224 |
+
# The last message must be a user or tool message in serving mode or an assistant message in finetuning mode
|
225 |
+
last_message_role = message.role
|
226 |
+
if self._mode == ValidationMode.finetuning:
|
227 |
+
if last_message_role != Roles.assistant:
|
228 |
+
raise InvalidMessageStructureException(
|
229 |
+
f"Expected last role Assistant for finetuning but got {last_message_role}"
|
230 |
+
)
|
231 |
+
else:
|
232 |
+
bad_assistant = isinstance(message, AssistantMessage) and not message.prefix
|
233 |
+
bad_role = message.role not in {Roles.user, Roles.tool}
|
234 |
+
if bad_assistant and bad_role:
|
235 |
+
raise InvalidMessageStructureException(
|
236 |
+
f"Expected last role User or Tool (or Assistant with prefix True) for serving"
|
237 |
+
f" but got {last_message_role}"
|
238 |
+
)
|
239 |
+
|
240 |
+
def _validate_message_list_structure(self, messages: List[UATS]) -> None:
|
241 |
+
"""
|
242 |
+
Validates the structure of the list of messages
|
243 |
+
|
244 |
+
For example the messages must be in the correct order of user/assistant/tool
|
245 |
+
"""
|
246 |
+
|
247 |
+
if len(messages) == 0:
|
248 |
+
raise InvalidMessageStructureException("Conversation must have at least one message")
|
249 |
+
|
250 |
+
# If we have one message it must be a user or a system message
|
251 |
+
if len(messages) == 1:
|
252 |
+
if messages[0].role not in {Roles.user, Roles.system}:
|
253 |
+
raise InvalidMessageStructureException("Conversation must start with a user message or system message")
|
254 |
+
|
255 |
+
# Always check the last message if in fine-tuning mode
|
256 |
+
if self._mode == ValidationMode.finetuning or len(messages) > 1:
|
257 |
+
self._validate_last_message(messages[-1])
|
258 |
+
|
259 |
+
self._validate_message_order(messages)
|
260 |
+
self._validate_tool_calls_followed_by_tool_messages(messages)
|
261 |
+
|
262 |
+
def _validate_message_list_content(self, messages: List[UATS]) -> None:
|
263 |
+
"""
|
264 |
+
Validates the content of the messages
|
265 |
+
"""
|
266 |
+
|
267 |
+
for idx, message in enumerate(messages):
|
268 |
+
if message.role == Roles.user:
|
269 |
+
self._validate_user_message(message)
|
270 |
+
elif message.role == Roles.assistant:
|
271 |
+
self._validate_assistant_message(message, is_last_message=idx == len(messages) - 1)
|
272 |
+
elif message.role == Roles.tool:
|
273 |
+
self._validate_tool_message(message)
|
274 |
+
elif message.role == Roles.system:
|
275 |
+
self._validate_system_message(message)
|
276 |
+
else:
|
277 |
+
raise InvalidRequestException(f"Unsupported message type {type(message)}")
|
278 |
+
|
279 |
+
|
280 |
+
class MistralRequestValidatorV3(MistralRequestValidator):
|
281 |
+
def _validate_tool_message(self, message: ToolMessageType) -> None:
|
282 |
+
"""
|
283 |
+
Checks:
|
284 |
+
- The tool name is valid
|
285 |
+
- Tool call id is valid
|
286 |
+
"""
|
287 |
+
if message.name is not None:
|
288 |
+
if not re.match(r"^[a-zA-Z0-9_-]{1,64}$", message.name):
|
289 |
+
raise InvalidToolMessageException(
|
290 |
+
f"Function name was {message.name} but must be a-z, A-Z, 0-9, "
|
291 |
+
"or contain underscores and dashes, with a maximum length of 64."
|
292 |
+
)
|
293 |
+
|
294 |
+
if message.tool_call_id is None:
|
295 |
+
raise InvalidRequestException("Tool call id has to be defined.")
|
296 |
+
|
297 |
+
if not re.match(r"^[a-zA-Z0-9]{9}$", message.tool_call_id):
|
298 |
+
raise InvalidToolMessageException(
|
299 |
+
f"Tool call id was {message.tool_call_id} but must be a-z, A-Z, 0-9, with a length of 9."
|
300 |
+
)
|
301 |
+
|
302 |
+
def _validate_tool_call(self, tool_call: ToolCall, is_last_message: bool) -> None:
|
303 |
+
"""
|
304 |
+
Validate that the tool call has a valid ID
|
305 |
+
"""
|
306 |
+
if tool_call.id != "null":
|
307 |
+
if not re.match(r"^[a-zA-Z0-9]{9}$", tool_call.id):
|
308 |
+
raise InvalidFunctionCallException(
|
309 |
+
f"Tool call id was {tool_call.id} but must be a-z, A-Z, 0-9, with a length of 9."
|
310 |
+
)
|
311 |
+
if self._mode == ValidationMode.finetuning and not is_last_message and tool_call.id == "null":
|
312 |
+
err_message = "Tool call id of assistant message that is not last has to be defined in finetuning mode."
|
313 |
+
raise InvalidFunctionCallException(err_message)
|
314 |
+
|
315 |
+
if self._mode == ValidationMode.serving and tool_call.id == "null":
|
316 |
+
raise InvalidFunctionCallException("Tool call id has to be defined in serving mode.")
|
317 |
+
|
318 |
+
self._validate_function_call(tool_call.function)
|
319 |
+
|
320 |
+
def _validate_last_message(self, message: UATS) -> None:
|
321 |
+
super()._validate_last_message(message)
|
322 |
+
|
323 |
+
if self._mode == ValidationMode.finetuning:
|
324 |
+
# in finetuning mode it has to be an assistant message
|
325 |
+
# as checked by parent `_validate_last_message`
|
326 |
+
if message.tool_calls is not None:
|
327 |
+
for tool_call in message.tool_calls:
|
328 |
+
self._validate_tool_call(tool_call, is_last_message=True)
|
.venv/lib/python3.11/site-packages/mistral_common/protocol/utils.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import uuid
|
2 |
+
|
3 |
+
|
4 |
+
def random_uuid() -> str:
|
5 |
+
return str(uuid.uuid4().hex)
|
.venv/lib/python3.11/site-packages/mistral_common/py.typed
ADDED
File without changes
|
.venv/lib/python3.11/site-packages/numpy/polynomial/tests/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (195 Bytes). View file
|
|
.venv/lib/python3.11/site-packages/numpy/polynomial/tests/__pycache__/test_hermite_e.cpython-311.pyc
ADDED
Binary file (38.6 kB). View file
|
|
.venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/INSTALLER
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
pip
|
.venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/LICENSE
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Apache License
|
2 |
+
Version 2.0, January 2004
|
3 |
+
http://www.apache.org/licenses/
|
4 |
+
|
5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
6 |
+
|
7 |
+
1. Definitions.
|
8 |
+
|
9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
11 |
+
|
12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
13 |
+
the copyright owner that is granting the License.
|
14 |
+
|
15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
16 |
+
other entities that control, are controlled by, or are under common
|
17 |
+
control with that entity. For the purposes of this definition,
|
18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
19 |
+
direction or management of such entity, whether by contract or
|
20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
22 |
+
|
23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
24 |
+
exercising permissions granted by this License.
|
25 |
+
|
26 |
+
"Source" form shall mean the preferred form for making modifications,
|
27 |
+
including but not limited to software source code, documentation
|
28 |
+
source, and configuration files.
|
29 |
+
|
30 |
+
"Object" form shall mean any form resulting from mechanical
|
31 |
+
transformation or translation of a Source form, including but
|
32 |
+
not limited to compiled object code, generated documentation,
|
33 |
+
and conversions to other media types.
|
34 |
+
|
35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
36 |
+
Object form, made available under the License, as indicated by a
|
37 |
+
copyright notice that is included in or attached to the work
|
38 |
+
(an example is provided in the Appendix below).
|
39 |
+
|
40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
41 |
+
form, that is based on (or derived from) the Work and for which the
|
42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
44 |
+
of this License, Derivative Works shall not include works that remain
|
45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
46 |
+
the Work and Derivative Works thereof.
|
47 |
+
|
48 |
+
"Contribution" shall mean any work of authorship, including
|
49 |
+
the original version of the Work and any modifications or additions
|
50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
54 |
+
means any form of electronic, verbal, or written communication sent
|
55 |
+
to the Licensor or its representatives, including but not limited to
|
56 |
+
communication on electronic mailing lists, source code control systems,
|
57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
59 |
+
excluding communication that is conspicuously marked or otherwise
|
60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
61 |
+
|
62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
64 |
+
subsequently incorporated within the Work.
|
65 |
+
|
66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
71 |
+
Work and such Derivative Works in Source or Object form.
|
72 |
+
|
73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
76 |
+
(except as stated in this section) patent license to make, have made,
|
77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
78 |
+
where such license applies only to those patent claims licensable
|
79 |
+
by such Contributor that are necessarily infringed by their
|
80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
82 |
+
institute patent litigation against any entity (including a
|
83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
84 |
+
or a Contribution incorporated within the Work constitutes direct
|
85 |
+
or contributory patent infringement, then any patent licenses
|
86 |
+
granted to You under this License for that Work shall terminate
|
87 |
+
as of the date such litigation is filed.
|
88 |
+
|
89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
90 |
+
Work or Derivative Works thereof in any medium, with or without
|
91 |
+
modifications, and in Source or Object form, provided that You
|
92 |
+
meet the following conditions:
|
93 |
+
|
94 |
+
(a) You must give any other recipients of the Work or
|
95 |
+
Derivative Works a copy of this License; and
|
96 |
+
|
97 |
+
(b) You must cause any modified files to carry prominent notices
|
98 |
+
stating that You changed the files; and
|
99 |
+
|
100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
101 |
+
that You distribute, all copyright, patent, trademark, and
|
102 |
+
attribution notices from the Source form of the Work,
|
103 |
+
excluding those notices that do not pertain to any part of
|
104 |
+
the Derivative Works; and
|
105 |
+
|
106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
107 |
+
distribution, then any Derivative Works that You distribute must
|
108 |
+
include a readable copy of the attribution notices contained
|
109 |
+
within such NOTICE file, excluding those notices that do not
|
110 |
+
pertain to any part of the Derivative Works, in at least one
|
111 |
+
of the following places: within a NOTICE text file distributed
|
112 |
+
as part of the Derivative Works; within the Source form or
|
113 |
+
documentation, if provided along with the Derivative Works; or,
|
114 |
+
within a display generated by the Derivative Works, if and
|
115 |
+
wherever such third-party notices normally appear. The contents
|
116 |
+
of the NOTICE file are for informational purposes only and
|
117 |
+
do not modify the License. You may add Your own attribution
|
118 |
+
notices within Derivative Works that You distribute, alongside
|
119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
120 |
+
that such additional attribution notices cannot be construed
|
121 |
+
as modifying the License.
|
122 |
+
|
123 |
+
You may add Your own copyright statement to Your modifications and
|
124 |
+
may provide additional or different license terms and conditions
|
125 |
+
for use, reproduction, or distribution of Your modifications, or
|
126 |
+
for any such Derivative Works as a whole, provided Your use,
|
127 |
+
reproduction, and distribution of the Work otherwise complies with
|
128 |
+
the conditions stated in this License.
|
129 |
+
|
130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
132 |
+
by You to the Licensor shall be under the terms and conditions of
|
133 |
+
this License, without any additional terms or conditions.
|
134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
135 |
+
the terms of any separate license agreement you may have executed
|
136 |
+
with Licensor regarding such Contributions.
|
137 |
+
|
138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
140 |
+
except as required for reasonable and customary use in describing the
|
141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
142 |
+
|
143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
144 |
+
agreed to in writing, Licensor provides the Work (and each
|
145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
147 |
+
implied, including, without limitation, any warranties or conditions
|
148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
150 |
+
appropriateness of using or redistributing the Work and assume any
|
151 |
+
risks associated with Your exercise of permissions under this License.
|
152 |
+
|
153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
154 |
+
whether in tort (including negligence), contract, or otherwise,
|
155 |
+
unless required by applicable law (such as deliberate and grossly
|
156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
157 |
+
liable to You for damages, including any direct, indirect, special,
|
158 |
+
incidental, or consequential damages of any character arising as a
|
159 |
+
result of this License or out of the use or inability to use the
|
160 |
+
Work (including but not limited to damages for loss of goodwill,
|
161 |
+
work stoppage, computer failure or malfunction, or any and all
|
162 |
+
other commercial damages or losses), even if such Contributor
|
163 |
+
has been advised of the possibility of such damages.
|
164 |
+
|
165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
168 |
+
or other liability obligations and/or rights consistent with this
|
169 |
+
License. However, in accepting such obligations, You may act only
|
170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
171 |
+
of any other Contributor, and only if You agree to indemnify,
|
172 |
+
defend, and hold each Contributor harmless for any liability
|
173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
174 |
+
of your accepting any such warranty or additional liability.
|
175 |
+
|
176 |
+
END OF TERMS AND CONDITIONS
|
177 |
+
|
178 |
+
APPENDIX: How to apply the Apache License to your work.
|
179 |
+
|
180 |
+
To apply the Apache License to your work, attach the following
|
181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
182 |
+
replaced with your own identifying information. (Don't include
|
183 |
+
the brackets!) The text should be enclosed in the appropriate
|
184 |
+
comment syntax for the file format. We also recommend that a
|
185 |
+
file or class name and description of purpose be included on the
|
186 |
+
same "printed page" as the copyright notice for easier
|
187 |
+
identification within third-party archives.
|
188 |
+
|
189 |
+
Copyright [yyyy] [name of copyright owner]
|
190 |
+
|
191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
192 |
+
you may not use this file except in compliance with the License.
|
193 |
+
You may obtain a copy of the License at
|
194 |
+
|
195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
196 |
+
|
197 |
+
Unless required by applicable law or agreed to in writing, software
|
198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
200 |
+
See the License for the specific language governing permissions and
|
201 |
+
limitations under the License.
|
.venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/METADATA
ADDED
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Metadata-Version: 2.2
|
2 |
+
Name: vllm
|
3 |
+
Version: 0.7.2
|
4 |
+
Summary: A high-throughput and memory-efficient inference and serving engine for LLMs
|
5 |
+
Home-page: https://github.com/vllm-project/vllm
|
6 |
+
Author: vLLM Team
|
7 |
+
License: Apache 2.0
|
8 |
+
Project-URL: Homepage, https://github.com/vllm-project/vllm
|
9 |
+
Project-URL: Documentation, https://vllm.readthedocs.io/en/latest/
|
10 |
+
Classifier: Programming Language :: Python :: 3.9
|
11 |
+
Classifier: Programming Language :: Python :: 3.10
|
12 |
+
Classifier: Programming Language :: Python :: 3.11
|
13 |
+
Classifier: Programming Language :: Python :: 3.12
|
14 |
+
Classifier: License :: OSI Approved :: Apache Software License
|
15 |
+
Classifier: Intended Audience :: Developers
|
16 |
+
Classifier: Intended Audience :: Information Technology
|
17 |
+
Classifier: Intended Audience :: Science/Research
|
18 |
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
19 |
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
20 |
+
Requires-Python: >=3.9
|
21 |
+
Description-Content-Type: text/markdown
|
22 |
+
License-File: LICENSE
|
23 |
+
Requires-Dist: psutil
|
24 |
+
Requires-Dist: sentencepiece
|
25 |
+
Requires-Dist: numpy<2.0.0
|
26 |
+
Requires-Dist: requests>=2.26.0
|
27 |
+
Requires-Dist: tqdm
|
28 |
+
Requires-Dist: blake3
|
29 |
+
Requires-Dist: py-cpuinfo
|
30 |
+
Requires-Dist: transformers>=4.48.2
|
31 |
+
Requires-Dist: tokenizers>=0.19.1
|
32 |
+
Requires-Dist: protobuf
|
33 |
+
Requires-Dist: fastapi<0.113.0,>=0.107.0; python_version < "3.9"
|
34 |
+
Requires-Dist: fastapi!=0.113.*,!=0.114.0,>=0.107.0; python_version >= "3.9"
|
35 |
+
Requires-Dist: aiohttp
|
36 |
+
Requires-Dist: openai>=1.52.0
|
37 |
+
Requires-Dist: uvicorn[standard]
|
38 |
+
Requires-Dist: pydantic>=2.9
|
39 |
+
Requires-Dist: prometheus_client>=0.18.0
|
40 |
+
Requires-Dist: pillow
|
41 |
+
Requires-Dist: prometheus-fastapi-instrumentator>=7.0.0
|
42 |
+
Requires-Dist: tiktoken>=0.6.0
|
43 |
+
Requires-Dist: lm-format-enforcer<0.11,>=0.10.9
|
44 |
+
Requires-Dist: outlines==0.1.11
|
45 |
+
Requires-Dist: lark==1.2.2
|
46 |
+
Requires-Dist: xgrammar>=0.1.6; platform_machine == "x86_64"
|
47 |
+
Requires-Dist: typing_extensions>=4.10
|
48 |
+
Requires-Dist: filelock>=3.16.1
|
49 |
+
Requires-Dist: partial-json-parser
|
50 |
+
Requires-Dist: pyzmq
|
51 |
+
Requires-Dist: msgspec
|
52 |
+
Requires-Dist: gguf==0.10.0
|
53 |
+
Requires-Dist: importlib_metadata
|
54 |
+
Requires-Dist: mistral_common[opencv]>=1.5.0
|
55 |
+
Requires-Dist: pyyaml
|
56 |
+
Requires-Dist: six>=1.16.0; python_version > "3.11"
|
57 |
+
Requires-Dist: setuptools>=74.1.1; python_version > "3.11"
|
58 |
+
Requires-Dist: einops
|
59 |
+
Requires-Dist: compressed-tensors==0.9.1
|
60 |
+
Requires-Dist: depyf==0.18.0
|
61 |
+
Requires-Dist: cloudpickle
|
62 |
+
Requires-Dist: ray[default]>=2.9
|
63 |
+
Requires-Dist: nvidia-ml-py>=12.560.30
|
64 |
+
Requires-Dist: torch==2.5.1
|
65 |
+
Requires-Dist: torchaudio==2.5.1
|
66 |
+
Requires-Dist: torchvision==0.20.1
|
67 |
+
Requires-Dist: xformers==0.0.28.post3; platform_system == "Linux" and platform_machine == "x86_64"
|
68 |
+
Provides-Extra: tensorizer
|
69 |
+
Requires-Dist: tensorizer>=2.9.0; extra == "tensorizer"
|
70 |
+
Provides-Extra: runai
|
71 |
+
Requires-Dist: runai-model-streamer; extra == "runai"
|
72 |
+
Requires-Dist: runai-model-streamer-s3; extra == "runai"
|
73 |
+
Requires-Dist: boto3; extra == "runai"
|
74 |
+
Provides-Extra: audio
|
75 |
+
Requires-Dist: librosa; extra == "audio"
|
76 |
+
Requires-Dist: soundfile; extra == "audio"
|
77 |
+
Provides-Extra: video
|
78 |
+
Requires-Dist: decord; extra == "video"
|
79 |
+
Dynamic: author
|
80 |
+
Dynamic: classifier
|
81 |
+
Dynamic: description
|
82 |
+
Dynamic: description-content-type
|
83 |
+
Dynamic: home-page
|
84 |
+
Dynamic: license
|
85 |
+
Dynamic: project-url
|
86 |
+
Dynamic: provides-extra
|
87 |
+
Dynamic: requires-dist
|
88 |
+
Dynamic: requires-python
|
89 |
+
Dynamic: summary
|
90 |
+
|
91 |
+
<p align="center">
|
92 |
+
<picture>
|
93 |
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/vllm-project/vllm/main/docs/source/assets/logos/vllm-logo-text-dark.png">
|
94 |
+
<img alt="vLLM" src="https://raw.githubusercontent.com/vllm-project/vllm/main/docs/source/assets/logos/vllm-logo-text-light.png" width=55%>
|
95 |
+
</picture>
|
96 |
+
</p>
|
97 |
+
|
98 |
+
<h3 align="center">
|
99 |
+
Easy, fast, and cheap LLM serving for everyone
|
100 |
+
</h3>
|
101 |
+
|
102 |
+
<p align="center">
|
103 |
+
| <a href="https://docs.vllm.ai"><b>Documentation</b></a> | <a href="https://vllm.ai"><b>Blog</b></a> | <a href="https://arxiv.org/abs/2309.06180"><b>Paper</b></a> | <a href="https://x.com/vllm_project"><b>Twitter/X</b></a> | <a href="https://slack.vllm.ai"><b>Developer Slack</b></a> |
|
104 |
+
</p>
|
105 |
+
|
106 |
+
---
|
107 |
+
|
108 |
+
*Latest News* 🔥
|
109 |
+
- [2025/01] We are excited to announce the alpha release of vLLM V1: A major architectural upgrade with 1.7x speedup! Clean code, optimized execution loop, zero-overhead prefix caching, enhanced multimodal support, and more. Please check out our blog post [here](https://blog.vllm.ai/2025/01/27/v1-alpha-release.html).
|
110 |
+
- [2025/01] We hosted [the eighth vLLM meetup](https://lu.ma/zep56hui) with Google Cloud! Please find the meetup slides from vLLM team [here](https://docs.google.com/presentation/d/1epVkt4Zu8Jz_S5OhEHPc798emsYh2BwYfRuDDVEF7u4/edit?usp=sharing).
|
111 |
+
- [2024/12] vLLM joins [pytorch ecosystem](https://pytorch.org/blog/vllm-joins-pytorch)! Easy, Fast, and Cheap LLM Serving for Everyone!
|
112 |
+
- [2024/11] We hosted [the seventh vLLM meetup](https://lu.ma/h0qvrajz) with Snowflake! Please find the meetup slides from vLLM team [here](https://docs.google.com/presentation/d/1e3CxQBV3JsfGp30SwyvS3eM_tW-ghOhJ9PAJGK6KR54/edit?usp=sharing), and Snowflake team [here](https://docs.google.com/presentation/d/1qF3RkDAbOULwz9WK5TOltt2fE9t6uIc_hVNLFAaQX6A/edit?usp=sharing).
|
113 |
+
- [2024/10] We have just created a developer slack ([slack.vllm.ai](https://slack.vllm.ai)) focusing on coordinating contributions and discussing features. Please feel free to join us there!
|
114 |
+
- [2024/10] Ray Summit 2024 held a special track for vLLM! Please find the opening talk slides from the vLLM team [here](https://docs.google.com/presentation/d/1B_KQxpHBTRa_mDF-tR6i8rWdOU5QoTZNcEg2MKZxEHM/edit?usp=sharing). Learn more from the [talks](https://www.youtube.com/playlist?list=PLzTswPQNepXl6AQwifuwUImLPFRVpksjR) from other vLLM contributors and users!
|
115 |
+
- [2024/09] We hosted [the sixth vLLM meetup](https://lu.ma/87q3nvnh) with NVIDIA! Please find the meetup slides [here](https://docs.google.com/presentation/d/1wrLGwytQfaOTd5wCGSPNhoaW3nq0E-9wqyP7ny93xRs/edit?usp=sharing).
|
116 |
+
- [2024/07] We hosted [the fifth vLLM meetup](https://lu.ma/lp0gyjqr) with AWS! Please find the meetup slides [here](https://docs.google.com/presentation/d/1RgUD8aCfcHocghoP3zmXzck9vX3RCI9yfUAB2Bbcl4Y/edit?usp=sharing).
|
117 |
+
- [2024/07] In partnership with Meta, vLLM officially supports Llama 3.1 with FP8 quantization and pipeline parallelism! Please check out our blog post [here](https://blog.vllm.ai/2024/07/23/llama31.html).
|
118 |
+
- [2024/06] We hosted [the fourth vLLM meetup](https://lu.ma/agivllm) with Cloudflare and BentoML! Please find the meetup slides [here](https://docs.google.com/presentation/d/1iJ8o7V2bQEi0BFEljLTwc5G1S10_Rhv3beed5oB0NJ4/edit?usp=sharing).
|
119 |
+
- [2024/04] We hosted [the third vLLM meetup](https://robloxandvllmmeetup2024.splashthat.com/) with Roblox! Please find the meetup slides [here](https://docs.google.com/presentation/d/1A--47JAK4BJ39t954HyTkvtfwn0fkqtsL8NGFuslReM/edit?usp=sharing).
|
120 |
+
- [2024/01] We hosted [the second vLLM meetup](https://lu.ma/ygxbpzhl) with IBM! Please find the meetup slides [here](https://docs.google.com/presentation/d/12mI2sKABnUw5RBWXDYY-HtHth4iMSNcEoQ10jDQbxgA/edit?usp=sharing).
|
121 |
+
- [2023/10] We hosted [the first vLLM meetup](https://lu.ma/first-vllm-meetup) with a16z! Please find the meetup slides [here](https://docs.google.com/presentation/d/1QL-XPFXiFpDBh86DbEegFXBXFXjix4v032GhShbKf3s/edit?usp=sharing).
|
122 |
+
- [2023/08] We would like to express our sincere gratitude to [Andreessen Horowitz](https://a16z.com/2023/08/30/supporting-the-open-source-ai-community/) (a16z) for providing a generous grant to support the open-source development and research of vLLM.
|
123 |
+
- [2023/06] We officially released vLLM! FastChat-vLLM integration has powered [LMSYS Vicuna and Chatbot Arena](https://chat.lmsys.org) since mid-April. Check out our [blog post](https://vllm.ai).
|
124 |
+
|
125 |
+
---
|
126 |
+
## About
|
127 |
+
vLLM is a fast and easy-to-use library for LLM inference and serving.
|
128 |
+
|
129 |
+
Originally developed in the [Sky Computing Lab](https://sky.cs.berkeley.edu) at UC Berkeley, vLLM has evolved into a community-driven project with contributions from both academia and industry.
|
130 |
+
|
131 |
+
vLLM is fast with:
|
132 |
+
|
133 |
+
- State-of-the-art serving throughput
|
134 |
+
- Efficient management of attention key and value memory with [**PagedAttention**](https://blog.vllm.ai/2023/06/20/vllm.html)
|
135 |
+
- Continuous batching of incoming requests
|
136 |
+
- Fast model execution with CUDA/HIP graph
|
137 |
+
- Quantizations: [GPTQ](https://arxiv.org/abs/2210.17323), [AWQ](https://arxiv.org/abs/2306.00978), INT4, INT8, and FP8.
|
138 |
+
- Optimized CUDA kernels, including integration with FlashAttention and FlashInfer.
|
139 |
+
- Speculative decoding
|
140 |
+
- Chunked prefill
|
141 |
+
|
142 |
+
**Performance benchmark**: We include a performance benchmark at the end of [our blog post](https://blog.vllm.ai/2024/09/05/perf-update.html). It compares the performance of vLLM against other LLM serving engines ([TensorRT-LLM](https://github.com/NVIDIA/TensorRT-LLM), [SGLang](https://github.com/sgl-project/sglang) and [LMDeploy](https://github.com/InternLM/lmdeploy)). The implementation is under [nightly-benchmarks folder](.buildkite/nightly-benchmarks/) and you can [reproduce](https://github.com/vllm-project/vllm/issues/8176) this benchmark using our one-click runnable script.
|
143 |
+
|
144 |
+
vLLM is flexible and easy to use with:
|
145 |
+
|
146 |
+
- Seamless integration with popular Hugging Face models
|
147 |
+
- High-throughput serving with various decoding algorithms, including *parallel sampling*, *beam search*, and more
|
148 |
+
- Tensor parallelism and pipeline parallelism support for distributed inference
|
149 |
+
- Streaming outputs
|
150 |
+
- OpenAI-compatible API server
|
151 |
+
- Support NVIDIA GPUs, AMD CPUs and GPUs, Intel CPUs and GPUs, PowerPC CPUs, TPU, and AWS Neuron.
|
152 |
+
- Prefix caching support
|
153 |
+
- Multi-lora support
|
154 |
+
|
155 |
+
vLLM seamlessly supports most popular open-source models on HuggingFace, including:
|
156 |
+
- Transformer-like LLMs (e.g., Llama)
|
157 |
+
- Mixture-of-Expert LLMs (e.g., Mixtral, Deepseek-V2 and V3)
|
158 |
+
- Embedding Models (e.g. E5-Mistral)
|
159 |
+
- Multi-modal LLMs (e.g., LLaVA)
|
160 |
+
|
161 |
+
Find the full list of supported models [here](https://docs.vllm.ai/en/latest/models/supported_models.html).
|
162 |
+
|
163 |
+
## Getting Started
|
164 |
+
|
165 |
+
Install vLLM with `pip` or [from source](https://docs.vllm.ai/en/latest/getting_started/installation/gpu/index.html#build-wheel-from-source):
|
166 |
+
|
167 |
+
```bash
|
168 |
+
pip install vllm
|
169 |
+
```
|
170 |
+
|
171 |
+
Visit our [documentation](https://docs.vllm.ai/en/latest/) to learn more.
|
172 |
+
- [Installation](https://docs.vllm.ai/en/latest/getting_started/installation/index.html)
|
173 |
+
- [Quickstart](https://docs.vllm.ai/en/latest/getting_started/quickstart.html)
|
174 |
+
- [List of Supported Models](https://docs.vllm.ai/en/latest/models/supported_models.html)
|
175 |
+
|
176 |
+
## Contributing
|
177 |
+
|
178 |
+
We welcome and value any contributions and collaborations.
|
179 |
+
Please check out [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get involved.
|
180 |
+
|
181 |
+
## Sponsors
|
182 |
+
|
183 |
+
vLLM is a community project. Our compute resources for development and testing are supported by the following organizations. Thank you for your support!
|
184 |
+
|
185 |
+
<!-- Note: Please sort them in alphabetical order. -->
|
186 |
+
<!-- Note: Please keep these consistent with docs/source/community/sponsors.md -->
|
187 |
+
Cash Donations:
|
188 |
+
- a16z
|
189 |
+
- Dropbox
|
190 |
+
- Sequoia Capital
|
191 |
+
- Skywork AI
|
192 |
+
- ZhenFund
|
193 |
+
|
194 |
+
Compute Resources:
|
195 |
+
- AMD
|
196 |
+
- Anyscale
|
197 |
+
- AWS
|
198 |
+
- Crusoe Cloud
|
199 |
+
- Databricks
|
200 |
+
- DeepInfra
|
201 |
+
- Google Cloud
|
202 |
+
- Lambda Lab
|
203 |
+
- Nebius
|
204 |
+
- Novita AI
|
205 |
+
- NVIDIA
|
206 |
+
- Replicate
|
207 |
+
- Roblox
|
208 |
+
- RunPod
|
209 |
+
- Trainy
|
210 |
+
- UC Berkeley
|
211 |
+
- UC San Diego
|
212 |
+
|
213 |
+
Slack Sponsor: Anyscale
|
214 |
+
|
215 |
+
We also have an official fundraising venue through [OpenCollective](https://opencollective.com/vllm). We plan to use the fund to support the development, maintenance, and adoption of vLLM.
|
216 |
+
|
217 |
+
## Citation
|
218 |
+
|
219 |
+
If you use vLLM for your research, please cite our [paper](https://arxiv.org/abs/2309.06180):
|
220 |
+
```bibtex
|
221 |
+
@inproceedings{kwon2023efficient,
|
222 |
+
title={Efficient Memory Management for Large Language Model Serving with PagedAttention},
|
223 |
+
author={Woosuk Kwon and Zhuohan Li and Siyuan Zhuang and Ying Sheng and Lianmin Zheng and Cody Hao Yu and Joseph E. Gonzalez and Hao Zhang and Ion Stoica},
|
224 |
+
booktitle={Proceedings of the ACM SIGOPS 29th Symposium on Operating Systems Principles},
|
225 |
+
year={2023}
|
226 |
+
}
|
227 |
+
```
|
228 |
+
|
229 |
+
## Contact Us
|
230 |
+
|
231 |
+
* For technical questions and feature requests, please use Github issues or discussions.
|
232 |
+
* For discussing with fellow users and coordinating contributions and development, please use Slack.
|
233 |
+
* For security disclosures, please use Github's security advisory feature.
|
234 |
+
* For collaborations and partnerships, please contact us at vllm-questions AT lists.berkeley.edu.
|
235 |
+
|
236 |
+
## Media Kit
|
237 |
+
|
238 |
+
* If you wish to use vLLM's logo, please refer to [our media kit repo](https://github.com/vllm-project/media-kit).
|
.venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/RECORD
ADDED
The diff for this file is too large to render.
See raw diff
|
|
.venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/REQUESTED
ADDED
File without changes
|
.venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/WHEEL
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Wheel-Version: 1.0
|
2 |
+
Generator: setuptools (75.8.0)
|
3 |
+
Root-Is-Purelib: false
|
4 |
+
Tag: cp38-abi3-linux_x86_64
|
5 |
+
|
.venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/entry_points.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
[console_scripts]
|
2 |
+
vllm = vllm.scripts:main
|
.venv/lib/python3.11/site-packages/vllm-0.7.2.dist-info/top_level.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
vllm
|
.venv/lib/python3.11/site-packages/xgrammar/__init__.py
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from . import testing
|
2 |
+
from .compiler import CompiledGrammar, GrammarCompiler
|
3 |
+
from .contrib import hf
|
4 |
+
from .grammar import Grammar, StructuralTagItem
|
5 |
+
from .matcher import (
|
6 |
+
GrammarMatcher,
|
7 |
+
allocate_token_bitmask,
|
8 |
+
apply_token_bitmask_inplace,
|
9 |
+
bitmask_dtype,
|
10 |
+
get_bitmask_shape,
|
11 |
+
reset_token_bitmask,
|
12 |
+
)
|
13 |
+
from .tokenizer_info import TokenizerInfo, VocabType
|
.venv/lib/python3.11/site-packages/xgrammar/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (835 Bytes). View file
|
|
.venv/lib/python3.11/site-packages/xgrammar/__pycache__/base.cpython-311.pyc
ADDED
Binary file (3.43 kB). View file
|
|
.venv/lib/python3.11/site-packages/xgrammar/__pycache__/compiler.cpython-311.pyc
ADDED
Binary file (9.18 kB). View file
|
|
.venv/lib/python3.11/site-packages/xgrammar/__pycache__/grammar.cpython-311.pyc
ADDED
Binary file (14.4 kB). View file
|
|