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 7, 07:45 UTC
[Refactor] Clean up processor kwargs extraction (#35872)
Signed-off-by: DarkLight1337 <tlleungac@connect.ust.hk>
Cyrus Leung committed
Mar 4, 2026 at 11:53 UTC
e3793961674af8bf01208b2216542ad00ae325e6
2 files changed
+55
-50
tests/transformers_utils/test_processor.py
+6
-5
@@ -7,7 +7,8 @@ from transformers.processing_utils import ProcessingKwargs
7
from typing_extensions import Unpack
8
9
from vllm.transformers_utils.processor import (
10
- get_processor_kwargs_from_processor,
10
+ get_processor_kwargs_keys,
11
+ get_processor_kwargs_type,
12
)
13
14
@@ -35,7 +36,7 @@ def _assert_has_all_expected(keys: set[str]) -> None:
36
assert k in keys
37
38
38
-# Path 1: __call__ method has kwargs: Unpack[*ProcessingKwargs]
39
+# Path 1: __call__ method has kwargs: Unpack[*ProcessorKwargs]
40
class _ProcWithUnpack:
41
def __call__(self, *args, **kwargs: Unpack[_FakeProcessorKwargs]): # type: ignore
42
return None
@@ -43,11 +44,11 @@ class _ProcWithUnpack:
44
45
def test_get_processor_kwargs_from_processor_unpack_path_returns_full_union():
46
proc = _ProcWithUnpack()
46
- keys = get_processor_kwargs_from_processor(proc)
47
+ keys = get_processor_kwargs_keys(get_processor_kwargs_type(proc))
48
_assert_has_all_expected(keys)
49
50
50
-# ---- Path 2: No Unpack, fallback to scanning *ProcessingKwargs in module ----
51
+# ---- Path 2: No Unpack, fallback to scanning *ProcessorKwargs in module ----
52
53
54
class _ProcWithoutUnpack:
@@ -62,5 +63,5 @@ def test_get_processor_kwargs_from_processor_module_scan_returns_full_union():
63
assert hasattr(mod, "_FakeProcessorKwargs")
64
65
proc = _ProcWithoutUnpack()
65
- keys = get_processor_kwargs_from_processor(proc)
66
+ keys = get_processor_kwargs_keys(get_processor_kwargs_type(proc))
67
_assert_has_all_expected(keys)
vllm/transformers_utils/processor.py
+49
-45
@@ -111,29 +111,6 @@ def _get_processor_factory_fn(processor_cls: type | tuple[type, ...]):
111
return processor_cls
112
113
114
-@lru_cache
115
-def _collect_dynamic_keys_from_processing_kwargs(kwargs_cls: type) -> set[str]:
116
- dynamic_kwargs: set[str] = set()
117
- if kwargs_cls is None:
118
- return dynamic_kwargs
119
- # get kwargs annotations in processor
120
- # merge text_kwargs / images_kwargs / videos_kwargs / audio_kwargs
121
- kwargs_type_annotations = get_type_hints(kwargs_cls)
122
- for kw_type in ("text_kwargs", "images_kwargs", "videos_kwargs", "audio_kwargs"):
123
- if kw_type in kwargs_type_annotations:
124
- # Use __annotations__ instead of get_type_hints() to avoid
125
- # NameError from unresolved forward references (e.g.
126
- # PILImageResampling). We only need key names, not types.
127
- kw_cls = kwargs_type_annotations[kw_type]
128
- kw_annotations: dict[str, Any] = {}
129
- for base in reversed(kw_cls.__mro__):
130
- kw_annotations.update(getattr(base, "__annotations__", {}))
131
- for kw_name in kw_annotations:
132
- dynamic_kwargs.add(kw_name)
133
- dynamic_kwargs |= {"text_kwargs", "images_kwargs", "videos_kwargs", "audio_kwargs"}
134
- return dynamic_kwargs
135
-
136
-
114
def _merge_mm_kwargs(
115
model_config: "ModelConfig",
116
processor_cls: type | tuple[type, ...],
@@ -224,38 +201,63 @@ cached_get_processor = lru_cache(get_processor)
201
202
203
@lru_cache
227
-def get_processor_kwargs_from_processor(processor: _P) -> set[str]:
204
+def get_processor_kwargs_type(
205
+ processor: ProcessorMixin,
206
+) -> type[processing_utils.ProcessingKwargs]:
207
try:
208
# get kwargs annotations in processor
230
- call_kwargs = inspect.signature(type(processor).__call__).parameters.get(
231
- "kwargs"
232
- )
209
+ call_params = inspect.signature(type(processor).__call__).parameters
210
+ call_kwargs = call_params.get("kwargs")
211
call_kwargs_annotations = call_kwargs.annotation if call_kwargs else None
212
+
213
# if the processor has explicit kwargs annotation, use it
214
if call_kwargs_annotations not in (None, inspect._empty):
215
# get_type_hints will parse all type annotations at runtime,
216
# and if an annotation refers to a type or
217
# name that hasn’t been imported or defined, it will raise an error.
218
# So we use __annotations__ to get the raw annotations directly.
240
- return _collect_dynamic_keys_from_processing_kwargs(
241
- get_args(call_kwargs_annotations)[0]
242
- )
243
- # otherwise, try to get from ProcessingKwargs
244
- else:
245
- module_name = type(processor).__module__
246
- mod = importlib.import_module(module_name)
247
- # find *ProcessingKwargs in the module
248
- processor_kwargs: set[str] = set()
249
- for name, obj in vars(mod).items():
250
- if name.endswith("ProcessingKwargs"):
251
- processor_kwargs = (
252
- processor_kwargs
253
- | _collect_dynamic_keys_from_processing_kwargs(obj)
254
- )
255
- return processor_kwargs
219
+ return get_args(call_kwargs_annotations)[0]
220
+
221
+ # otherwise, try to get from ProcessorKwargs
222
+ module_name = type(processor).__module__
223
+ mod = importlib.import_module(module_name)
224
+ for name, obj in vars(mod).items():
225
+ if name.endswith("ProcessorKwargs"):
226
+ return obj
227
+
228
except Exception:
229
logger.exception("Failed to collect processor kwargs")
258
- return set()
230
+
231
+ return processing_utils.ProcessingKwargs
232
+
233
+
234
+@lru_cache
235
+def get_processor_kwargs_keys(
236
+ kwargs_cls: type[processing_utils.ProcessingKwargs],
237
+) -> set[str]:
238
+ dynamic_kwargs: set[str] = set()
239
+ modality_kwargs = {"text_kwargs", "images_kwargs", "videos_kwargs", "audio_kwargs"}
240
+
241
+ try:
242
+ # get kwargs annotations in processor
243
+ # merge text_kwargs / images_kwargs / videos_kwargs / audio_kwargs
244
+ kwargs_type_annotations = get_type_hints(kwargs_cls)
245
+ for kw_type in modality_kwargs:
246
+ if kw_type in kwargs_type_annotations:
247
+ # Use __annotations__ instead of get_type_hints() to avoid
248
+ # NameError from unresolved forward references (e.g.
249
+ # PILImageResampling). We only need key names, not types.
250
+ kw_cls = kwargs_type_annotations[kw_type]
251
+ kw_annotations: dict[str, Any] = {}
252
+ for base in reversed(kw_cls.__mro__):
253
+ kw_annotations.update(getattr(base, "__annotations__", {}))
254
+ for kw_name in kw_annotations:
255
+ dynamic_kwargs.add(kw_name)
256
+
257
+ except Exception:
258
+ logger.exception("Failed to collect processor kwargs")
259
+
260
+ return dynamic_kwargs | modality_kwargs
261
262
263
def cached_get_processor_without_dynamic_kwargs(
@@ -275,7 +277,9 @@ def cached_get_processor_without_dynamic_kwargs(
277
)
278
279
# Step 2: use temporary processor collect dynamic keys
278
- dynamic_keys = get_processor_kwargs_from_processor(processor)
280
+ dynamic_keys = get_processor_kwargs_keys(
281
+ get_processor_kwargs_type(processor) # type: ignore[arg-type]
282
+ )
283
284
# Step 3: use dynamic_keys filter kwargs
285
filtered_kwargs = {k: v for k, v in kwargs.items() if k not in dynamic_keys}