A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 14, 05:30 UTC
[Chore] Separate out `vllm.utils.importlib` (#27022)
Signed-off-by: DarkLight1337 <tlleungac@connect.ust.hk>
Cyrus Leung committed
Oct 17, 2025 at 08:48 UTC
4d4d6bad1981f2907e43e353d263b15c7a6dab28
41 files changed
+417
-391
tests/model_executor/model_loader/tensorizer_loader/test_tensorizer.py
+1
-1
@@ -27,7 +27,7 @@ from vllm.model_executor.model_loader.tensorizer import (
27
from vllm.model_executor.model_loader.tensorizer_loader import (
28
BLACKLISTED_TENSORIZER_ARGS,
29
)
30
-from vllm.utils import PlaceholderModule
30
+from vllm.utils.import_utils import PlaceholderModule
31
32
from .conftest import DummyExecutor, assert_from_collective_rpc
33
tests/utils_/test_import_utils.py
new
+46
@@ -0,0 +1,46 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+import pytest
4
+
5
+from vllm.utils.import_utils import PlaceholderModule
6
+
7
+
8
+def _raises_module_not_found():
9
+ return pytest.raises(ModuleNotFoundError, match="No module named")
10
+
11
+
12
+def test_placeholder_module_error_handling():
13
+ placeholder = PlaceholderModule("placeholder_1234")
14
+
15
+ with _raises_module_not_found():
16
+ int(placeholder)
17
+
18
+ with _raises_module_not_found():
19
+ placeholder()
20
+
21
+ with _raises_module_not_found():
22
+ _ = placeholder.some_attr
23
+
24
+ with _raises_module_not_found():
25
+ # Test conflict with internal __name attribute
26
+ _ = placeholder.name
27
+
28
+ # OK to print the placeholder or use it in a f-string
29
+ _ = repr(placeholder)
30
+ _ = str(placeholder)
31
+
32
+ # No error yet; only error when it is used downstream
33
+ placeholder_attr = placeholder.placeholder_attr("attr")
34
+
35
+ with _raises_module_not_found():
36
+ int(placeholder_attr)
37
+
38
+ with _raises_module_not_found():
39
+ placeholder_attr()
40
+
41
+ with _raises_module_not_found():
42
+ _ = placeholder_attr.some_attr
43
+
44
+ with _raises_module_not_found():
45
+ # Test conflict with internal __module attribute
46
+ _ = placeholder_attr.module
tests/utils_/test_utils.py
-41
@@ -24,7 +24,6 @@ from vllm.transformers_utils.detokenizer_utils import convert_ids_list_to_tokens
24
from vllm.utils import (
25
FlexibleArgumentParser,
26
MemorySnapshot,
27
- PlaceholderModule,
27
bind_kv_cache,
28
common_broadcastable_dtype,
29
current_stream,
@@ -475,46 +474,6 @@ def test_common_broadcastable_dtype(dtypes, expected_result):
474
assert common_broadcastable_dtype(dtypes) == expected_result
475
476
478
-def test_placeholder_module_error_handling():
479
- placeholder = PlaceholderModule("placeholder_1234")
480
-
481
- def build_ctx():
482
- return pytest.raises(ModuleNotFoundError, match="No module named")
483
-
484
- with build_ctx():
485
- int(placeholder)
486
-
487
- with build_ctx():
488
- placeholder()
489
-
490
- with build_ctx():
491
- _ = placeholder.some_attr
492
-
493
- with build_ctx():
494
- # Test conflict with internal __name attribute
495
- _ = placeholder.name
496
-
497
- # OK to print the placeholder or use it in a f-string
498
- _ = repr(placeholder)
499
- _ = str(placeholder)
500
-
501
- # No error yet; only error when it is used downstream
502
- placeholder_attr = placeholder.placeholder_attr("attr")
503
-
504
- with build_ctx():
505
- int(placeholder_attr)
506
-
507
- with build_ctx():
508
- placeholder_attr()
509
-
510
- with build_ctx():
511
- _ = placeholder_attr.some_attr
512
-
513
- with build_ctx():
514
- # Test conflict with internal __module attribute
515
- _ = placeholder_attr.module
516
-
517
-
477
def test_model_specification(
478
parser_with_config, cli_config_file, cli_config_file_with_model
479
):
tests/v1/attention/utils.py
+1
-1
@@ -20,7 +20,7 @@ from vllm.config import (
20
VllmConfig,
21
)
22
from vllm.config.model import ModelDType
23
-from vllm.utils import resolve_obj_by_qualname
23
+from vllm.utils.import_utils import resolve_obj_by_qualname
24
from vllm.v1.attention.backends.utils import (
25
AttentionMetadataBuilder,
26
CommonAttentionMetadata,
vllm/assets/audio.py
+1
-1
@@ -8,7 +8,7 @@ from urllib.parse import urljoin
8
9
import numpy.typing as npt
10
11
-from vllm.utils import PlaceholderModule
11
+from vllm.utils.import_utils import PlaceholderModule
12
13
from .base import VLLM_S3_BUCKET_URL, get_vllm_public_assets
14
vllm/assets/video.py
+1
-1
@@ -10,7 +10,7 @@ import numpy.typing as npt
10
from huggingface_hub import hf_hub_download
11
from PIL import Image
12
13
-from vllm.utils import PlaceholderModule
13
+from vllm.utils.import_utils import PlaceholderModule
14
15
from .base import get_cache_dir
16
vllm/attention/backends/registry.py
+1
-1
@@ -4,7 +4,7 @@
4
5
import enum
6
7
-from vllm.utils import resolve_obj_by_qualname
7
+from vllm.utils.import_utils import resolve_obj_by_qualname
8
9
10
class _Backend(enum.Enum):
vllm/attention/selector.py
+2
-1
@@ -13,7 +13,8 @@ import vllm.envs as envs
13
from vllm.attention.backends.abstract import AttentionBackend
14
from vllm.attention.backends.registry import _Backend, backend_name_to_enum
15
from vllm.logger import init_logger
16
-from vllm.utils import STR_BACKEND_ENV_VAR, resolve_obj_by_qualname
16
+from vllm.utils import STR_BACKEND_ENV_VAR
17
+from vllm.utils.import_utils import resolve_obj_by_qualname
18
19
logger = init_logger(__name__)
20
vllm/benchmarks/datasets.py
+1
-1
@@ -39,7 +39,7 @@ from vllm.lora.utils import get_adapter_absolute_path
39
from vllm.multimodal import MultiModalDataDict
40
from vllm.multimodal.image import convert_image_mode
41
from vllm.transformers_utils.tokenizer import AnyTokenizer
42
-from vllm.utils import PlaceholderModule
42
+from vllm.utils.import_utils import PlaceholderModule
43
44
try:
45
from datasets import load_dataset
vllm/compilation/backends.py
+2
-1
@@ -24,7 +24,8 @@ from vllm.compilation.partition_rules import (
24
from vllm.config import CompilationConfig, CUDAGraphMode, VllmConfig
25
from vllm.logger import init_logger
26
from vllm.platforms import current_platform
27
-from vllm.utils import is_torch_equal_or_newer, resolve_obj_by_qualname
27
+from vllm.utils import is_torch_equal_or_newer
28
+from vllm.utils.import_utils import resolve_obj_by_qualname
29
30
from .caching import VllmSerializableFunction
31
from .compiler_interface import (
vllm/compilation/decorators.py
+2
-1
@@ -21,7 +21,8 @@ from vllm.compilation.wrapper import TorchCompileWrapperWithCustomDispatcher
21
from vllm.config import CompilationMode, VllmConfig, set_current_vllm_config
22
from vllm.logger import init_logger
23
from vllm.sequence import IntermediateTensors
24
-from vllm.utils import resolve_obj_by_qualname, supports_dynamo
24
+from vllm.utils import supports_dynamo
25
+from vllm.utils.import_utils import resolve_obj_by_qualname
26
27
from .monitor import start_monitoring_torch_compile
28
vllm/config/compilation.py
+2
-1
@@ -16,7 +16,8 @@ from vllm.compilation.inductor_pass import CallableInductorPass, InductorPass
16
from vllm.config.utils import config
17
from vllm.logger import init_logger
18
from vllm.platforms import current_platform
19
-from vllm.utils import is_torch_equal_or_newer, resolve_obj_by_qualname
19
+from vllm.utils import is_torch_equal_or_newer
20
+from vllm.utils.import_utils import resolve_obj_by_qualname
21
22
if TYPE_CHECKING:
23
from vllm.config import VllmConfig
vllm/config/model.py
+2
-1
@@ -41,7 +41,8 @@ from vllm.transformers_utils.config import (
41
)
42
from vllm.transformers_utils.runai_utils import ObjectStorageModel, is_runai_obj_uri
43
from vllm.transformers_utils.utils import maybe_model_redirect
44
-from vllm.utils import LayerBlockType, LazyLoader, common_broadcastable_dtype
44
+from vllm.utils import LayerBlockType, common_broadcastable_dtype
45
+from vllm.utils.import_utils import LazyLoader
46
47
if TYPE_CHECKING:
48
from transformers import PretrainedConfig
vllm/config/speculative.py
+1
-1
@@ -13,7 +13,7 @@ import vllm.envs as envs
13
from vllm.config.parallel import ParallelConfig
14
from vllm.config.utils import config
15
from vllm.logger import init_logger
16
-from vllm.utils import LazyLoader
16
+from vllm.utils.import_utils import LazyLoader
17
18
if TYPE_CHECKING:
19
from transformers import PretrainedConfig
vllm/distributed/parallel_state.py
+1
-1
@@ -52,9 +52,9 @@ from vllm.logger import init_logger
52
from vllm.utils import (
53
direct_register_custom_op,
54
get_distributed_init_method,
55
- resolve_obj_by_qualname,
55
supports_custom_op,
56
)
57
+from vllm.utils.import_utils import resolve_obj_by_qualname
58
59
60
@dataclass
vllm/entrypoints/openai/protocol.py
+2
-1
@@ -81,7 +81,8 @@ from vllm.sampling_params import (
81
SamplingParams,
82
StructuredOutputsParams,
83
)
84
-from vllm.utils import random_uuid, resolve_obj_by_qualname
84
+from vllm.utils import random_uuid
85
+from vllm.utils.import_utils import resolve_obj_by_qualname
86
87
EMBED_DTYPE_TO_TORCH_DTYPE = {
88
"float32": torch.float32,
vllm/entrypoints/openai/speech_to_text.py
+1
-1
@@ -32,7 +32,7 @@ from vllm.inputs.data import PromptType
32
from vllm.logger import init_logger
33
from vllm.model_executor.models import SupportsTranscription
34
from vllm.outputs import RequestOutput
35
-from vllm.utils import PlaceholderModule
35
+from vllm.utils.import_utils import PlaceholderModule
36
37
try:
38
import librosa
vllm/entrypoints/openai/tool_parsers/abstract_tool_parser.py
+1
-1
@@ -12,8 +12,8 @@ from vllm.entrypoints.openai.protocol import (
12
)
13
from vllm.logger import init_logger
14
from vllm.transformers_utils.tokenizer import AnyTokenizer
15
-from vllm.utils import import_from_path
15
from vllm.utils.collections import is_list_of
16
+from vllm.utils.import_utils import import_from_path
17
18
logger = init_logger(__name__)
19
vllm/lora/punica_wrapper/punica_selector.py
+1
-1
@@ -3,7 +3,7 @@
3
4
from vllm.logger import init_logger
5
from vllm.platforms import current_platform
6
-from vllm.utils import resolve_obj_by_qualname
6
+from vllm.utils.import_utils import resolve_obj_by_qualname
7
8
from .punica_base import PunicaWrapperBase
9
vllm/model_executor/layers/pooler.py
+1
-1
@@ -17,7 +17,7 @@ from vllm.logger import init_logger
17
from vllm.model_executor.models.adapters import _load_st_projector
18
from vllm.pooling_params import PoolingParams
19
from vllm.tasks import PoolingTask
20
-from vllm.utils import resolve_obj_by_qualname
20
+from vllm.utils.import_utils import resolve_obj_by_qualname
21
from vllm.v1.outputs import PoolerOutput
22
from vllm.v1.pool.metadata import PoolingCursor, PoolingMetadata
23
vllm/model_executor/model_loader/tensorizer.py
+2
-1
@@ -26,7 +26,8 @@ from vllm.config import ModelConfig, ParallelConfig, VllmConfig, set_current_vll
26
from vllm.logger import init_logger
27
from vllm.model_executor.layers.vocab_parallel_embedding import VocabParallelEmbedding
28
from vllm.platforms import current_platform
29
-from vllm.utils import FlexibleArgumentParser, PlaceholderModule
29
+from vllm.utils import FlexibleArgumentParser
30
+from vllm.utils.import_utils import PlaceholderModule
31
32
if TYPE_CHECKING:
33
from vllm.engine.arg_utils import EngineArgs
vllm/model_executor/model_loader/weight_utils.py
+1
-1
@@ -34,7 +34,7 @@ from vllm.model_executor.layers.quantization import (
34
get_quantization_config,
35
)
36
from vllm.platforms import current_platform
37
-from vllm.utils import PlaceholderModule
37
+from vllm.utils.import_utils import PlaceholderModule
38
39
try:
40
from runai_model_streamer import SafetensorsStreamer
vllm/multimodal/audio.py
+1
-1
@@ -8,7 +8,7 @@ from typing import Literal
8
import numpy as np
9
import numpy.typing as npt
10
11
-from vllm.utils import PlaceholderModule
11
+from vllm.utils.import_utils import PlaceholderModule
12
13
from .base import MediaIO
14
vllm/multimodal/inputs.py
+1
-1
@@ -22,8 +22,8 @@ from typing import (
22
import numpy as np
23
from typing_extensions import NotRequired, TypeVar, deprecated
24
25
-from vllm.utils import LazyLoader
25
from vllm.utils.collections import full_groupby, is_list_of
26
+from vllm.utils.import_utils import LazyLoader
27
from vllm.utils.jsontree import json_map_leaves
28
29
if TYPE_CHECKING:
vllm/multimodal/parse.py
+1
-1
@@ -19,8 +19,8 @@ import numpy as np
19
import torch
20
from typing_extensions import assert_never
21
22
-from vllm.utils import LazyLoader
22
from vllm.utils.collections import is_list_of
23
+from vllm.utils.import_utils import LazyLoader
24
25
from .audio import AudioResampler
26
from .inputs import (
vllm/platforms/__init__.py
+2
-1
@@ -7,7 +7,8 @@ from typing import TYPE_CHECKING
7
8
from vllm import envs
9
from vllm.plugins import PLATFORM_PLUGINS_GROUP, load_plugins_by_group
10
-from vllm.utils import resolve_obj_by_qualname, supports_xccl
10
+from vllm.utils import supports_xccl
11
+from vllm.utils.import_utils import resolve_obj_by_qualname
12
13
from .interface import CpuArchEnum, Platform, PlatformEnum
14
vllm/plugins/io_processors/__init__.py
+1
-1
@@ -6,7 +6,7 @@ import logging
6
from vllm.config import VllmConfig
7
from vllm.plugins import IO_PROCESSOR_PLUGINS_GROUP, load_plugins_by_group
8
from vllm.plugins.io_processors.interface import IOProcessor
9
-from vllm.utils import resolve_obj_by_qualname
9
+from vllm.utils.import_utils import resolve_obj_by_qualname
10
11
logger = logging.getLogger(__name__)
12
vllm/reasoning/abs_reasoning_parsers.py
+1
-1
@@ -8,8 +8,8 @@ from functools import cached_property
8
from typing import TYPE_CHECKING, Any
9
10
from vllm.logger import init_logger
11
-from vllm.utils import import_from_path
11
from vllm.utils.collections import is_list_of
12
+from vllm.utils.import_utils import import_from_path
13
14
if TYPE_CHECKING:
15
from vllm.entrypoints.openai.protocol import (
vllm/transformers_utils/runai_utils.py
+1
-1
@@ -9,7 +9,7 @@ import signal
9
from vllm import envs
10
from vllm.assets.base import get_cache_dir
11
from vllm.logger import init_logger
12
-from vllm.utils import PlaceholderModule
12
+from vllm.utils.import_utils import PlaceholderModule
13
14
logger = init_logger(__name__)
15
vllm/transformers_utils/s3_utils.py
+1
-1
@@ -4,7 +4,7 @@
4
import fnmatch
5
from typing import TYPE_CHECKING, Optional
6
7
-from vllm.utils import PlaceholderModule
7
+from vllm.utils.import_utils import PlaceholderModule
8
9
if TYPE_CHECKING:
10
from botocore.client import BaseClient
vllm/utils/__init__.py
-313
@@ -8,8 +8,6 @@ import gc
8
import getpass
9
import hashlib
10
import importlib
11
-import importlib.metadata
12
-import importlib.util
11
import inspect
12
import ipaddress
13
import json
@@ -25,7 +23,6 @@ import textwrap
23
import threading
24
import time
25
import traceback
28
-import types
26
import uuid
27
import warnings
28
import weakref
@@ -68,7 +65,6 @@ import zmq.asyncio
65
from packaging import version
66
from packaging.version import Version
67
from torch.library import Library
71
-from typing_extensions import Never
68
69
import vllm.envs as envs
70
from vllm.logger import enable_trace_function_call, init_logger
@@ -801,8 +797,6 @@ def find_nccl_include_paths() -> list[str] | None:
797
paths.append(inc)
798
799
try:
804
- import importlib.util
805
-
800
spec = importlib.util.find_spec("nvidia.nccl")
801
if spec and getattr(spec, "submodule_search_locations", None):
802
for loc in spec.submodule_search_locations:
@@ -1560,253 +1554,6 @@ def get_cuda_view_from_cpu_tensor(cpu_tensor: torch.Tensor) -> torch.Tensor:
1554
return torch.ops._C.get_cuda_view_from_cpu_tensor(cpu_tensor)
1555
1556
1563
-def import_from_path(module_name: str, file_path: str | os.PathLike):
1564
- """
1565
- Import a Python file according to its file path.
1566
-
1567
- Based on the official recipe:
1568
- https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
1569
- """
1570
- spec = importlib.util.spec_from_file_location(module_name, file_path)
1571
- if spec is None:
1572
- raise ModuleNotFoundError(f"No module named '{module_name}'")
1573
-
1574
- assert spec.loader is not None
1575
-
1576
- module = importlib.util.module_from_spec(spec)
1577
- sys.modules[module_name] = module
1578
- spec.loader.exec_module(module)
1579
- return module
1580
-
1581
-
1582
-@cache
1583
-def get_vllm_optional_dependencies():
1584
- metadata = importlib.metadata.metadata("vllm")
1585
- requirements = metadata.get_all("Requires-Dist", [])
1586
- extras = metadata.get_all("Provides-Extra", [])
1587
-
1588
- return {
1589
- extra: [
1590
- re.split(r";|>=|<=|==", req)[0]
1591
- for req in requirements
1592
- if req.endswith(f'extra == "{extra}"')
1593
- ]
1594
- for extra in extras
1595
- }
1596
-
1597
-
1598
-class _PlaceholderBase:
1599
- """
1600
- Disallows downstream usage of placeholder modules.
1601
-
1602
- We need to explicitly override each dunder method because
1603
- [`__getattr__`][vllm.utils._PlaceholderBase.__getattr__]
1604
- is not called when they are accessed.
1605
-
1606
- Info:
1607
- [Special method lookup](https://docs.python.org/3/reference/datamodel.html#special-lookup)
1608
- """
1609
-
1610
- def __getattr__(self, key: str) -> Never:
1611
- """
1612
- The main class should implement this to throw an error
1613
- for attribute accesses representing downstream usage.
1614
- """
1615
- raise NotImplementedError
1616
-
1617
- # [Basic customization]
1618
-
1619
- def __lt__(self, other: object):
1620
- return self.__getattr__("__lt__")
1621
-
1622
- def __le__(self, other: object):
1623
- return self.__getattr__("__le__")
1624
-
1625
- def __eq__(self, other: object):
1626
- return self.__getattr__("__eq__")
1627
-
1628
- def __ne__(self, other: object):
1629
- return self.__getattr__("__ne__")
1630
-
1631
- def __gt__(self, other: object):
1632
- return self.__getattr__("__gt__")
1633
-
1634
- def __ge__(self, other: object):
1635
- return self.__getattr__("__ge__")
1636
-
1637
- def __hash__(self):
1638
- return self.__getattr__("__hash__")
1639
-
1640
- def __bool__(self):
1641
- return self.__getattr__("__bool__")
1642
-
1643
- # [Callable objects]
1644
-
1645
- def __call__(self, *args: object, **kwargs: object):
1646
- return self.__getattr__("__call__")
1647
-
1648
- # [Container types]
1649
-
1650
- def __len__(self):
1651
- return self.__getattr__("__len__")
1652
-
1653
- def __getitem__(self, key: object):
1654
- return self.__getattr__("__getitem__")
1655
-
1656
- def __setitem__(self, key: object, value: object):
1657
- return self.__getattr__("__setitem__")
1658
-
1659
- def __delitem__(self, key: object):
1660
- return self.__getattr__("__delitem__")
1661
-
1662
- # __missing__ is optional according to __getitem__ specification,
1663
- # so it is skipped
1664
-
1665
- # __iter__ and __reversed__ have a default implementation
1666
- # based on __len__ and __getitem__, so they are skipped.
1667
-
1668
- # [Numeric Types]
1669
-
1670
- def __add__(self, other: object):
1671
- return self.__getattr__("__add__")
1672
-
1673
- def __sub__(self, other: object):
1674
- return self.__getattr__("__sub__")
1675
-
1676
- def __mul__(self, other: object):
1677
- return self.__getattr__("__mul__")
1678
-
1679
- def __matmul__(self, other: object):
1680
- return self.__getattr__("__matmul__")
1681
-
1682
- def __truediv__(self, other: object):
1683
- return self.__getattr__("__truediv__")
1684
-
1685
- def __floordiv__(self, other: object):
1686
- return self.__getattr__("__floordiv__")
1687
-
1688
- def __mod__(self, other: object):
1689
- return self.__getattr__("__mod__")
1690
-
1691
- def __divmod__(self, other: object):
1692
- return self.__getattr__("__divmod__")
1693
-
1694
- def __pow__(self, other: object, modulo: object = ...):
1695
- return self.__getattr__("__pow__")
1696
-
1697
- def __lshift__(self, other: object):
1698
- return self.__getattr__("__lshift__")
1699
-
1700
- def __rshift__(self, other: object):
1701
- return self.__getattr__("__rshift__")
1702
-
1703
- def __and__(self, other: object):
1704
- return self.__getattr__("__and__")
1705
-
1706
- def __xor__(self, other: object):
1707
- return self.__getattr__("__xor__")
1708
-
1709
- def __or__(self, other: object):
1710
- return self.__getattr__("__or__")
1711
-
1712
- # r* and i* methods have lower priority than
1713
- # the methods for left operand so they are skipped
1714
-
1715
- def __neg__(self):
1716
- return self.__getattr__("__neg__")
1717
-
1718
- def __pos__(self):
1719
- return self.__getattr__("__pos__")
1720
-
1721
- def __abs__(self):
1722
- return self.__getattr__("__abs__")
1723
-
1724
- def __invert__(self):
1725
- return self.__getattr__("__invert__")
1726
-
1727
- # __complex__, __int__ and __float__ have a default implementation
1728
- # based on __index__, so they are skipped.
1729
-
1730
- def __index__(self):
1731
- return self.__getattr__("__index__")
1732
-
1733
- def __round__(self, ndigits: object = ...):
1734
- return self.__getattr__("__round__")
1735
-
1736
- def __trunc__(self):
1737
- return self.__getattr__("__trunc__")
1738
-
1739
- def __floor__(self):
1740
- return self.__getattr__("__floor__")
1741
-
1742
- def __ceil__(self):
1743
- return self.__getattr__("__ceil__")
1744
-
1745
- # [Context managers]
1746
-
1747
- def __enter__(self):
1748
- return self.__getattr__("__enter__")
1749
-
1750
- def __exit__(self, *args: object, **kwargs: object):
1751
- return self.__getattr__("__exit__")
1752
-
1753
-
1754
-class PlaceholderModule(_PlaceholderBase):
1755
- """
1756
- A placeholder object to use when a module does not exist.
1757
-
1758
- This enables more informative errors when trying to access attributes
1759
- of a module that does not exist.
1760
- """
1761
-
1762
- def __init__(self, name: str) -> None:
1763
- super().__init__()
1764
-
1765
- # Apply name mangling to avoid conflicting with module attributes
1766
- self.__name = name
1767
-
1768
- def placeholder_attr(self, attr_path: str):
1769
- return _PlaceholderModuleAttr(self, attr_path)
1770
-
1771
- def __getattr__(self, key: str):
1772
- name = self.__name
1773
-
1774
- try:
1775
- importlib.import_module(name)
1776
- except ImportError as exc:
1777
- for extra, names in get_vllm_optional_dependencies().items():
1778
- if name in names:
1779
- msg = f"Please install vllm[{extra}] for {extra} support"
1780
- raise ImportError(msg) from exc
1781
-
1782
- raise exc
1783
-
1784
- raise AssertionError(
1785
- "PlaceholderModule should not be used "
1786
- "when the original module can be imported"
1787
- )
1788
-
1789
-
1790
-class _PlaceholderModuleAttr(_PlaceholderBase):
1791
- def __init__(self, module: PlaceholderModule, attr_path: str) -> None:
1792
- super().__init__()
1793
-
1794
- # Apply name mangling to avoid conflicting with module attributes
1795
- self.__module = module
1796
- self.__attr_path = attr_path
1797
-
1798
- def placeholder_attr(self, attr_path: str):
1799
- return _PlaceholderModuleAttr(self.__module, f"{self.__attr_path}.{attr_path}")
1800
-
1801
- def __getattr__(self, key: str):
1802
- getattr(self.__module, f"{self.__attr_path}.{key}")
1803
-
1804
- raise AssertionError(
1805
- "PlaceholderModule should not be used "
1806
- "when the original module can be imported"
1807
- )
1808
-
1809
-
1557
# create a library to hold the custom op
1558
vllm_lib = Library("vllm", "FRAGMENT") # noqa
1559
@@ -1871,15 +1618,6 @@ def direct_register_custom_op(
1618
my_lib._register_fake(op_name, fake_impl)
1619
1620
1874
-def resolve_obj_by_qualname(qualname: str) -> Any:
1875
- """
1876
- Resolve an object by its fully-qualified class name.
1877
- """
1878
- module_name, obj_name = qualname.rsplit(".", 1)
1879
- module = importlib.import_module(module_name)
1880
- return getattr(module, obj_name)
1881
-
1882
-
1621
def kill_process_tree(pid: int):
1622
"""
1623
Kills all descendant processes of the given pid by sending SIGKILL.
@@ -2427,57 +2165,6 @@ def warn_for_unimplemented_methods(cls: type[T]) -> type[T]:
2165
return cls
2166
2167
2430
-class LazyLoader(types.ModuleType):
2431
- """
2432
- LazyLoader module borrowed from Tensorflow
2433
- https://github.com/tensorflow/tensorflow/blob/main/tensorflow/python/util/lazy_loader.py
2434
- with an addition of "module caching".
2435
-
2436
- Lazily import a module, mainly to avoid pulling in large dependencies.
2437
- Modules such as `xgrammar` might do additional side effects, so we
2438
- only want to use this when it is needed, delaying all eager effects
2439
- """
2440
-
2441
- def __init__(
2442
- self,
2443
- local_name: str,
2444
- parent_module_globals: dict[str, Any],
2445
- name: str,
2446
- ):
2447
- self._local_name = local_name
2448
- self._parent_module_globals = parent_module_globals
2449
- self._module: types.ModuleType | None = None
2450
-
2451
- super().__init__(str(name))
2452
-
2453
- def _load(self) -> types.ModuleType:
2454
- # Import the target module and insert it into the parent's namespace
2455
- try:
2456
- module = importlib.import_module(self.__name__)
2457
- self._parent_module_globals[self._local_name] = module
2458
- # The additional add to sys.modules
2459
- # ensures library is actually loaded.
2460
- sys.modules[self._local_name] = module
2461
- except ModuleNotFoundError as err:
2462
- raise err from None
2463
-
2464
- # Update this object's dict so that if someone keeps a
2465
- # reference to the LazyLoader, lookups are efficient
2466
- # (__getattr__ is only called on lookups that fail).
2467
- self.__dict__.update(module.__dict__)
2468
- return module
2469
-
2470
- def __getattr__(self, item: Any) -> Any:
2471
- if self._module is None:
2472
- self._module = self._load()
2473
- return getattr(self._module, item)
2474
-
2475
- def __dir__(self) -> list[str]:
2476
- if self._module is None:
2477
- self._module = self._load()
2478
- return dir(self._module)
2479
-
2480
-
2168
@contextlib.contextmanager
2169
def cprofile_context(save_file: str | None = None):
2170
"""Run a cprofile
vllm/utils/import_utils.py
new
+326
@@ -0,0 +1,326 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
4
+"""
5
+Contains helpers related to importing modules.
6
+
7
+This is similar in concept to the `importlib` module.
8
+"""
9
+
10
+import importlib.metadata
11
+import importlib.util
12
+import os
13
+import sys
14
+from functools import cache
15
+from types import ModuleType
16
+from typing import Any
17
+
18
+import regex as re
19
+from typing_extensions import Never
20
+
21
+
22
+def import_from_path(module_name: str, file_path: str | os.PathLike):
23
+ """
24
+ Import a Python file according to its file path.
25
+
26
+ Based on the official recipe:
27
+ https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
28
+ """
29
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
30
+ if spec is None:
31
+ raise ModuleNotFoundError(f"No module named {module_name!r}")
32
+
33
+ assert spec.loader is not None
34
+
35
+ module = importlib.util.module_from_spec(spec)
36
+ sys.modules[module_name] = module
37
+ spec.loader.exec_module(module)
38
+ return module
39
+
40
+
41
+def resolve_obj_by_qualname(qualname: str) -> Any:
42
+ """
43
+ Resolve an object by its fully-qualified class name.
44
+ """
45
+ module_name, obj_name = qualname.rsplit(".", 1)
46
+ module = importlib.import_module(module_name)
47
+ return getattr(module, obj_name)
48
+
49
+
50
+@cache
51
+def get_vllm_optional_dependencies():
52
+ metadata = importlib.metadata.metadata("vllm")
53
+ requirements = metadata.get_all("Requires-Dist", [])
54
+ extras = metadata.get_all("Provides-Extra", [])
55
+
56
+ return {
57
+ extra: [
58
+ re.split(r";|>=|<=|==", req)[0]
59
+ for req in requirements
60
+ if req.endswith(f'extra == "{extra}"')
61
+ ]
62
+ for extra in extras
63
+ }
64
+
65
+
66
+class _PlaceholderBase:
67
+ """
68
+ Disallows downstream usage of placeholder modules.
69
+
70
+ We need to explicitly override each dunder method because
71
+ [`__getattr__`][vllm.utils.import_utils._PlaceholderBase.__getattr__]
72
+ is not called when they are accessed.
73
+
74
+ Info:
75
+ [Special method lookup](https://docs.python.org/3/reference/datamodel.html#special-lookup)
76
+ """
77
+
78
+ def __getattr__(self, key: str) -> Never:
79
+ """
80
+ The main class should implement this to throw an error
81
+ for attribute accesses representing downstream usage.
82
+ """
83
+ raise NotImplementedError
84
+
85
+ # [Basic customization]
86
+
87
+ def __lt__(self, other: object):
88
+ return self.__getattr__("__lt__")
89
+
90
+ def __le__(self, other: object):
91
+ return self.__getattr__("__le__")
92
+
93
+ def __eq__(self, other: object):
94
+ return self.__getattr__("__eq__")
95
+
96
+ def __ne__(self, other: object):
97
+ return self.__getattr__("__ne__")
98
+
99
+ def __gt__(self, other: object):
100
+ return self.__getattr__("__gt__")
101
+
102
+ def __ge__(self, other: object):
103
+ return self.__getattr__("__ge__")
104
+
105
+ def __hash__(self):
106
+ return self.__getattr__("__hash__")
107
+
108
+ def __bool__(self):
109
+ return self.__getattr__("__bool__")
110
+
111
+ # [Callable objects]
112
+
113
+ def __call__(self, *args: object, **kwargs: object):
114
+ return self.__getattr__("__call__")
115
+
116
+ # [Container types]
117
+
118
+ def __len__(self):
119
+ return self.__getattr__("__len__")
120
+
121
+ def __getitem__(self, key: object):
122
+ return self.__getattr__("__getitem__")
123
+
124
+ def __setitem__(self, key: object, value: object):
125
+ return self.__getattr__("__setitem__")
126
+
127
+ def __delitem__(self, key: object):
128
+ return self.__getattr__("__delitem__")
129
+
130
+ # __missing__ is optional according to __getitem__ specification,
131
+ # so it is skipped
132
+
133
+ # __iter__ and __reversed__ have a default implementation
134
+ # based on __len__ and __getitem__, so they are skipped.
135
+
136
+ # [Numeric Types]
137
+
138
+ def __add__(self, other: object):
139
+ return self.__getattr__("__add__")
140
+
141
+ def __sub__(self, other: object):
142
+ return self.__getattr__("__sub__")
143
+
144
+ def __mul__(self, other: object):
145
+ return self.__getattr__("__mul__")
146
+
147
+ def __matmul__(self, other: object):
148
+ return self.__getattr__("__matmul__")
149
+
150
+ def __truediv__(self, other: object):
151
+ return self.__getattr__("__truediv__")
152
+
153
+ def __floordiv__(self, other: object):
154
+ return self.__getattr__("__floordiv__")
155
+
156
+ def __mod__(self, other: object):
157
+ return self.__getattr__("__mod__")
158
+
159
+ def __divmod__(self, other: object):
160
+ return self.__getattr__("__divmod__")
161
+
162
+ def __pow__(self, other: object, modulo: object = ...):
163
+ return self.__getattr__("__pow__")
164
+
165
+ def __lshift__(self, other: object):
166
+ return self.__getattr__("__lshift__")
167
+
168
+ def __rshift__(self, other: object):
169
+ return self.__getattr__("__rshift__")
170
+
171
+ def __and__(self, other: object):
172
+ return self.__getattr__("__and__")
173
+
174
+ def __xor__(self, other: object):
175
+ return self.__getattr__("__xor__")
176
+
177
+ def __or__(self, other: object):
178
+ return self.__getattr__("__or__")
179
+
180
+ # r* and i* methods have lower priority than
181
+ # the methods for left operand so they are skipped
182
+
183
+ def __neg__(self):
184
+ return self.__getattr__("__neg__")
185
+
186
+ def __pos__(self):
187
+ return self.__getattr__("__pos__")
188
+
189
+ def __abs__(self):
190
+ return self.__getattr__("__abs__")
191
+
192
+ def __invert__(self):
193
+ return self.__getattr__("__invert__")
194
+
195
+ # __complex__, __int__ and __float__ have a default implementation
196
+ # based on __index__, so they are skipped.
197
+
198
+ def __index__(self):
199
+ return self.__getattr__("__index__")
200
+
201
+ def __round__(self, ndigits: object = ...):
202
+ return self.__getattr__("__round__")
203
+
204
+ def __trunc__(self):
205
+ return self.__getattr__("__trunc__")
206
+
207
+ def __floor__(self):
208
+ return self.__getattr__("__floor__")
209
+
210
+ def __ceil__(self):
211
+ return self.__getattr__("__ceil__")
212
+
213
+ # [Context managers]
214
+
215
+ def __enter__(self):
216
+ return self.__getattr__("__enter__")
217
+
218
+ def __exit__(self, *args: object, **kwargs: object):
219
+ return self.__getattr__("__exit__")
220
+
221
+
222
+class PlaceholderModule(_PlaceholderBase):
223
+ """
224
+ A placeholder object to use when a module does not exist.
225
+
226
+ This enables more informative errors when trying to access attributes
227
+ of a module that does not exist.
228
+ """
229
+
230
+ def __init__(self, name: str) -> None:
231
+ super().__init__()
232
+
233
+ # Apply name mangling to avoid conflicting with module attributes
234
+ self.__name = name
235
+
236
+ def placeholder_attr(self, attr_path: str):
237
+ return _PlaceholderModuleAttr(self, attr_path)
238
+
239
+ def __getattr__(self, key: str) -> Never:
240
+ name = self.__name
241
+
242
+ try:
243
+ importlib.import_module(name)
244
+ except ImportError as exc:
245
+ for extra, names in get_vllm_optional_dependencies().items():
246
+ if name in names:
247
+ msg = f"Please install vllm[{extra}] for {extra} support"
248
+ raise ImportError(msg) from exc
249
+
250
+ raise exc
251
+
252
+ raise AssertionError(
253
+ "PlaceholderModule should not be used "
254
+ "when the original module can be imported"
255
+ )
256
+
257
+
258
+class _PlaceholderModuleAttr(_PlaceholderBase):
259
+ def __init__(self, module: PlaceholderModule, attr_path: str) -> None:
260
+ super().__init__()
261
+
262
+ # Apply name mangling to avoid conflicting with module attributes
263
+ self.__module = module
264
+ self.__attr_path = attr_path
265
+
266
+ def placeholder_attr(self, attr_path: str):
267
+ return _PlaceholderModuleAttr(self.__module, f"{self.__attr_path}.{attr_path}")
268
+
269
+ def __getattr__(self, key: str) -> Never:
270
+ getattr(self.__module, f"{self.__attr_path}.{key}")
271
+
272
+ raise AssertionError(
273
+ "PlaceholderModule should not be used "
274
+ "when the original module can be imported"
275
+ )
276
+
277
+
278
+class LazyLoader(ModuleType):
279
+ """
280
+ `LazyLoader` module borrowed from [Tensorflow]
281
+ (https://github.com/tensorflow/tensorflow/blob/main/tensorflow/python/util/lazy_loader.py)
282
+ with an addition of "module caching".
283
+
284
+ Lazily import a module, mainly to avoid pulling in large dependencies.
285
+ Modules such as `xgrammar` might do additional side effects, so we
286
+ only want to use this when it is needed, delaying all eager effects.
287
+ """
288
+
289
+ def __init__(
290
+ self,
291
+ local_name: str,
292
+ parent_module_globals: dict[str, Any],
293
+ name: str,
294
+ ):
295
+ self._local_name = local_name
296
+ self._parent_module_globals = parent_module_globals
297
+ self._module: ModuleType | None = None
298
+
299
+ super().__init__(str(name))
300
+
301
+ def _load(self) -> ModuleType:
302
+ # Import the target module and insert it into the parent's namespace
303
+ try:
304
+ module = importlib.import_module(self.__name__)
305
+ self._parent_module_globals[self._local_name] = module
306
+ # The additional add to sys.modules
307
+ # ensures library is actually loaded.
308
+ sys.modules[self._local_name] = module
309
+ except ModuleNotFoundError as err:
310
+ raise err from None
311
+
312
+ # Update this object's dict so that if someone keeps a
313
+ # reference to the LazyLoader, lookups are efficient
314
+ # (__getattr__ is only called on lookups that fail).
315
+ self.__dict__.update(module.__dict__)
316
+ return module
317
+
318
+ def __getattr__(self, item: Any) -> Any:
319
+ if self._module is None:
320
+ self._module = self._load()
321
+ return getattr(self._module, item)
322
+
323
+ def __dir__(self) -> list[str]:
324
+ if self._module is None:
325
+ self._module = self._load()
326
+ return dir(self._module)
vllm/v1/engine/core.py
+1
-1
@@ -32,10 +32,10 @@ from vllm.utils import (
32
decorate_logs,
33
get_hash_fn_by_name,
34
make_zmq_socket,
35
- resolve_obj_by_qualname,
35
set_process_title,
36
)
37
from vllm.utils.gc_utils import maybe_attach_gc_debug_callback
38
+from vllm.utils.import_utils import resolve_obj_by_qualname
39
from vllm.v1.core.kv_cache_utils import (
40
BlockHash,
41
generate_scheduler_kv_cache_config,
vllm/v1/executor/abstract.py
+1
-1
@@ -14,7 +14,7 @@ from vllm.executor.uniproc_executor import ( # noqa
14
ExecutorWithExternalLauncher as ExecutorWithExternalLauncherV0,
15
)
16
from vllm.executor.uniproc_executor import UniProcExecutor as UniProcExecutorV0 # noqa
17
-from vllm.utils import resolve_obj_by_qualname
17
+from vllm.utils.import_utils import resolve_obj_by_qualname
18
from vllm.v1.core.sched.output import SchedulerOutput
19
from vllm.v1.kv_cache_interface import KVCacheConfig, KVCacheSpec
20
from vllm.v1.outputs import DraftTokenIds, ModelRunnerOutput
vllm/v1/structured_output/__init__.py
+1
-1
@@ -8,7 +8,7 @@ from vllm.config import VllmConfig
8
from vllm.logger import init_logger
9
from vllm.reasoning import ReasoningParserManager
10
from vllm.transformers_utils.tokenizer import init_tokenizer_from_configs
11
-from vllm.utils import LazyLoader
11
+from vllm.utils.import_utils import LazyLoader
12
from vllm.v1.structured_output.backend_guidance import GuidanceBackend
13
from vllm.v1.structured_output.backend_types import (
14
StructuredOutputBackend,
vllm/v1/structured_output/backend_guidance.py
+1
-1
@@ -11,7 +11,7 @@ import torch
11
12
from vllm.logger import init_logger
13
from vllm.sampling_params import SamplingParams
14
-from vllm.utils import LazyLoader
14
+from vllm.utils.import_utils import LazyLoader
15
from vllm.v1.structured_output.backend_types import (
16
StructuredOutputBackend,
17
StructuredOutputGrammar,
vllm/v1/structured_output/backend_lm_format_enforcer.py
+1
-1
@@ -10,7 +10,7 @@ import torch
10
from transformers import PreTrainedTokenizerBase
11
12
from vllm.sampling_params import SamplingParams
13
-from vllm.utils import LazyLoader
13
+from vllm.utils.import_utils import LazyLoader
14
from vllm.v1.structured_output.backend_types import (
15
StructuredOutputBackend,
16
StructuredOutputGrammar,
vllm/v1/structured_output/backend_outlines.py
+1
-1
@@ -12,7 +12,7 @@ import torch
12
from regex import escape as regex_escape
13
14
from vllm.sampling_params import SamplingParams
15
-from vllm.utils import LazyLoader
15
+from vllm.utils.import_utils import LazyLoader
16
from vllm.v1.structured_output.backend_types import (
17
StructuredOutputBackend,
18
StructuredOutputGrammar,
vllm/v1/structured_output/backend_xgrammar.py
+1
-1
@@ -11,7 +11,7 @@ import vllm.envs
11
from vllm.logger import init_logger
12
from vllm.sampling_params import SamplingParams
13
from vllm.transformers_utils.tokenizers.mistral import MistralTokenizer
14
-from vllm.utils import LazyLoader
14
+from vllm.utils.import_utils import LazyLoader
15
from vllm.v1.structured_output.backend_types import (
16
StructuredOutputBackend,
17
StructuredOutputGrammar,
vllm/v1/structured_output/utils.py
+1
-1
@@ -13,7 +13,7 @@ from diskcache import Cache
13
14
import vllm.envs as envs
15
from vllm.logger import init_logger
16
-from vllm.utils import LazyLoader
16
+from vllm.utils.import_utils import LazyLoader
17
18
if TYPE_CHECKING:
19
import outlines_core as oc
vllm/v1/worker/worker_base.py
+1
-1
@@ -15,11 +15,11 @@ from vllm.multimodal import MULTIMODAL_REGISTRY
15
from vllm.multimodal.cache import worker_receiver_cache_from_config
16
from vllm.utils import (
17
enable_trace_function_call_for_thread,
18
- resolve_obj_by_qualname,
18
run_method,
19
update_environment_variables,
20
warn_for_unimplemented_methods,
21
)
22
+from vllm.utils.import_utils import resolve_obj_by_qualname
23
from vllm.v1.kv_cache_interface import KVCacheSpec
24
25
if TYPE_CHECKING: