From 735bbaa93c4310131dabec3d8bf56bf51ebc5192 Mon Sep 17 00:00:00 2001 From: waynehacking8 Date: Fri, 19 Jun 2026 14:24:09 +0800 Subject: [PATCH 1/2] [Bugfix] Fix ImportError in get_chat_template for builtin chat-template names (#4533) `get_chat_template` (lmdeploy/cli/utils.py) imported `DEPRECATED_CHAT_TEMPLATE_NAMES` and `REMOVED_CHAT_TEMPLATE_NAMES` from `lmdeploy.model`, but those lists were removed in #4252 ([AsyncEngine Refactor 2/N] Remove deprecates from chat template). That refactor cleaned up model.py, cli.py, async_engine.py and the tests, but left the import (and its two guard blocks) dangling in cli/utils.py. As a result, passing any builtin chat-template name that is not a file path (e.g. `--chat-template internlm2`) to `lmdeploy serve api_server` or `lmdeploy chat` crashed with: ImportError: cannot import name 'DEPRECATED_CHAT_TEMPLATE_NAMES' from 'lmdeploy.model' before reaching the registry validation. Omitting `--chat-template`, or passing a `.json` file path, returns early, which is why it went unnoticed. Complete the refactor: drop the dead import and the removed-/deprecated-name guards, keep the `MODELS` registry check, and remove the now-unused module logger. Add regression tests in tests/test_lmdeploy/test_utils.py covering a builtin name, an unregistered name, and the None case. Co-authored-by: Claude --- lmdeploy/cli/utils.py | 15 ++------------- tests/test_lmdeploy/test_utils.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/lmdeploy/cli/utils.py b/lmdeploy/cli/utils.py index 1dda62a7e8..537db912df 100644 --- a/lmdeploy/cli/utils.py +++ b/lmdeploy/cli/utils.py @@ -7,10 +7,6 @@ from collections import defaultdict from typing import Any -from lmdeploy.utils import get_logger - -logger = get_logger('lmdeploy') - class DefaultsAndTypesHelpFormatter(argparse.HelpFormatter): """Formatter to output default value and type in help information.""" @@ -73,7 +69,7 @@ def get_chat_template(chat_template: str, model_path: str = None): Args: chat_template(str): it could be a builtin chat template name, or a chat template json file - model_path(str): the model path, used to check deprecated chat template names + model_path(str): the model path, passed through to the chat template config """ import os @@ -82,14 +78,7 @@ def get_chat_template(chat_template: str, model_path: str = None): if os.path.isfile(chat_template): return ChatTemplateConfig.from_json(chat_template) else: - from lmdeploy.model import DEPRECATED_CHAT_TEMPLATE_NAMES, MODELS, REMOVED_CHAT_TEMPLATE_NAMES - if chat_template in REMOVED_CHAT_TEMPLATE_NAMES: - raise ValueError(f"The chat template '{chat_template}' has been removed. " - f'Please refer to the latest chat templates in ' - f'https://lmdeploy.readthedocs.io/en/latest/advance/chat_template.html') - if chat_template in DEPRECATED_CHAT_TEMPLATE_NAMES: - logger.warning(f"The chat template '{chat_template}' is deprecated and fallback to hf chat template.") - chat_template = 'hf' + from lmdeploy.model import MODELS assert chat_template in MODELS.module_dict.keys(), \ f"chat template '{chat_template}' is not " \ f'registered. The builtin chat templates are: ' \ diff --git a/tests/test_lmdeploy/test_utils.py b/tests/test_lmdeploy/test_utils.py index 060c6a5ea5..f1e225d0e9 100644 --- a/tests/test_lmdeploy/test_utils.py +++ b/tests/test_lmdeploy/test_utils.py @@ -87,3 +87,34 @@ def test_get_and_verify_max_len(): assert (_get_and_verify_max_len(config, None) == 32768) assert (_get_and_verify_max_len(config, 1024) == 1024) assert (_get_and_verify_max_len(config, 102400) == 102400) + + +def test_get_chat_template_builtin_name(): + """A builtin chat-template name must resolve without crashing. + + Regression for #4533: get_chat_template imported DEPRECATED_CHAT_TEMPLATE_NAMES / REMOVED_CHAT_TEMPLATE_NAMES from + lmdeploy.model, which were removed in #4252, so any non-file --chat-template value raised ImportError before + reaching the registry check. + """ + from lmdeploy.cli.utils import get_chat_template + cfg = get_chat_template('llama2') + assert cfg is not None + assert cfg.model_name == 'llama2' + + +def test_get_chat_template_unregistered_name(): + """An unregistered name is rejected by the registry check, not by an + ImportError.""" + from lmdeploy.cli.utils import get_chat_template + raised = False + try: + get_chat_template('not-a-registered-template') + except AssertionError: + raised = True + assert raised, 'an unregistered chat template name should raise AssertionError' + + +def test_get_chat_template_none(): + """Passing no chat template returns None.""" + from lmdeploy.cli.utils import get_chat_template + assert get_chat_template(None) is None From c900106892baacb59b707a81911d4df326b6d267 Mon Sep 17 00:00:00 2001 From: waynehacking8 Date: Mon, 22 Jun 2026 15:24:24 +0800 Subject: [PATCH 2/2] [Bugfix] Address Copilot review: widen type hints and use pytest.raises - get_chat_template: annotate chat_template/model_path as `str | None` (both accept None in CLI flows and tests) and update docstring arg types. - test_get_chat_template_unregistered_name: replace manual try/except + boolean flag with pytest.raises(AssertionError) for clarity. --- lmdeploy/cli/utils.py | 6 +++--- tests/test_lmdeploy/test_utils.py | 7 ++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/lmdeploy/cli/utils.py b/lmdeploy/cli/utils.py index 537db912df..79e611e5a6 100644 --- a/lmdeploy/cli/utils.py +++ b/lmdeploy/cli/utils.py @@ -64,12 +64,12 @@ def get_lora_adapters(adapters: list[str]): return output -def get_chat_template(chat_template: str, model_path: str = None): +def get_chat_template(chat_template: str | None, model_path: str | None = None): """Get chat template config. Args: - chat_template(str): it could be a builtin chat template name, or a chat template json file - model_path(str): the model path, passed through to the chat template config + chat_template(str | None): it could be a builtin chat template name, or a chat template json file + model_path(str | None): the model path, passed through to the chat template config """ import os diff --git a/tests/test_lmdeploy/test_utils.py b/tests/test_lmdeploy/test_utils.py index f1e225d0e9..856e9d264f 100644 --- a/tests/test_lmdeploy/test_utils.py +++ b/tests/test_lmdeploy/test_utils.py @@ -1,3 +1,4 @@ +import pytest import torch from transformers import AutoConfig @@ -106,12 +107,8 @@ def test_get_chat_template_unregistered_name(): """An unregistered name is rejected by the registry check, not by an ImportError.""" from lmdeploy.cli.utils import get_chat_template - raised = False - try: + with pytest.raises(AssertionError): get_chat_template('not-a-registered-template') - except AssertionError: - raised = True - assert raised, 'an unregistered chat template name should raise AssertionError' def test_get_chat_template_none():