@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 4d4d6bad19
Fork 0

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: